From 8fdf3d7587223e12574ce27f0ae9eb762c25d2a5 Mon Sep 17 00:00:00 2001 From: Luis Manuel Diaz Angulo Date: Thu, 2 Jan 2025 12:22:56 +0100 Subject: [PATCH] Revert "Merge pull request #97 from OpenSEMBA/feature/smbjson" This reverts commit 3e8aa75a483f2744badcda90f33305d6ada6cabd, reversing changes made to bb537501d6472d9d0b63cf5a95bfbb0736bf9dc2. --- .github/workflows/ubuntu-gnu.yml | 68 ++ .github/workflows/ubuntu-intel.yml | 69 +++ .github/workflows/ubuntu-intelLLVM.yml | 68 ++ .github/workflows/ubuntu-nvidia.yml | 66 ++ .github/workflows/ubuntu.yml | 93 --- .github/workflows/windows-intelLLVM.yml | 36 +- doc/smbjson.md | 65 +- pytest.ini | 2 +- src_json_parser/mesh.F90 | 28 +- src_json_parser/smbjson.F90 | 581 ++++++++++-------- src_json_parser/smbjson_labels.F90 | 5 + test/pyWrapper/test_full_system.py | 7 +- test/pyWrapper/test_mtln_standalone.py | 7 - test/pyWrapper/utils.py | 11 - test/smbjson/test_parser.F90 | 11 +- .../coated_antenna/coated_antenna.fdtd.json | 6 +- testData/cases/holland/holland1981.fdtd.json | 3 +- .../cases/holland_with_dielectric.fdtd.json | 1 + .../cases/line_multiline_junction.fdtd.json | 5 + ...ne_multiline_junction_with_wires.fdtd.json | 5 + testData/cases/multilines_4port_box.fdtd.json | 6 +- .../multilines_4port_box_nobox.fdtd.json | 6 +- testData/cases/multilines_balun.fdtd.json | 6 +- testData/cases/multilines_opamp.fdtd.json | 6 +- testData/cases/opamp_saturation.fdtd.json | 3 +- testData/cases/paul_8_6_square.fdtd.json | 3 +- testData/cases/paul_8_6_triangle.fdtd.json | 3 +- testData/cases/paul_9_6.fdtd.json | 3 +- testData/cases/sgbc/sgbc.fdtd.json | 3 +- .../cases/shieldedPair/shieldedPair.fdtd.json | 9 +- testData/cases/sphere/sphere.fdtd.json | 3 +- testData/cases/spice_connectors.fdtd.json | 3 +- .../cases/towelHanger/towelHanger.fdtd.json | 6 +- testData/cases/wire_panel.fdtd.json | 3 +- .../input_examples/connectedWires.fdtd.json | 6 +- testData/input_examples/holland1981.fdtd.json | 3 +- .../large_airplane_mtln.fdtd.json | 66 +- testData/input_examples/mtln.fdtd.json | 27 +- testData/input_examples/sgbc.fdtd.json | 3 +- .../input_examples/shieldedPair.fdtd.json | 9 +- testData/input_examples/sphere.fdtd.json | 3 +- testData/input_examples/thinSlot.fdtd.json | 4 +- testData/input_examples/towelHanger.fdtd.json | 6 +- 43 files changed, 834 insertions(+), 493 deletions(-) create mode 100644 .github/workflows/ubuntu-gnu.yml create mode 100644 .github/workflows/ubuntu-intel.yml create mode 100644 .github/workflows/ubuntu-intelLLVM.yml create mode 100644 .github/workflows/ubuntu-nvidia.yml delete mode 100644 .github/workflows/ubuntu.yml diff --git a/.github/workflows/ubuntu-gnu.yml b/.github/workflows/ubuntu-gnu.yml new file mode 100644 index 00000000..633abaf5 --- /dev/null +++ b/.github/workflows/ubuntu-gnu.yml @@ -0,0 +1,68 @@ +name: ubuntu-gnu + +on: + pull_request: + branches: + - main + - dev + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +jobs: + + builds-and-test: + runs-on: ubuntu-latest + strategy: + matrix: + build-type: ["Debug", "Release"] + mpi: ["No", "Yes"] + mtln: ["Yes"] + hdf: ["Yes"] + + include: + - build-type: "Release" + mpi: "Yes" + mtln: "No" + hdf: "Yes" + + name: ${{matrix.build-type}}- mpi ${{matrix.mpi}} - mtln ${{matrix.mtln}} - hdf ${{matrix.hdf}} + + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + submodules: 'recursive' + + - name: Install required packages + run: | + sudo apt update + sudo apt install libhdf5-dev libopenmpi-dev + + - name: Build application + run: | + cmake -S . -B build \ + -DCMAKE_BUILD_TYPE=${{matrix.build-type}} \ + -DSEMBA_FDTD_ENABLE_MPI=${{matrix.mpi}} \ + -DSEMBA_FDTD_ENABLE_HDF=${{matrix.hdf}} \ + -DSEMBA_FDTD_ENABLE_MTLN=${{matrix.mtln}} + cmake --build build -j + + - name: Run fdtd unit tests + run: | + build/bin/fdtd_tests + + - name: Install python wrapper requirements + run: | + python -m pip install -r requirements.txt + + - name: Run all wrapper tests + if: matrix.mtln=='Yes' + run: python -m pytest test/ + + - name: Run non-mtln wrapper tests + if: matrix.mtln=='No' + run: python -m pytest -m 'not mtln' test/ + + diff --git a/.github/workflows/ubuntu-intel.yml b/.github/workflows/ubuntu-intel.yml new file mode 100644 index 00000000..047aa3f2 --- /dev/null +++ b/.github/workflows/ubuntu-intel.yml @@ -0,0 +1,69 @@ +name: ubuntu-intel + +on: + pull_request: + branches: + - main + - dev + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +jobs: + + builds-and-tests: + runs-on: ubuntu-latest + strategy: + matrix: + build-type: ["Debug", "Release"] + mpi: ["No"] + mtln: ["No"] + hdf: ["Yes"] + + + name: ${{matrix.build-type}}- mpi ${{matrix.mpi}} - mtln ${{matrix.mtln}} - hdf ${{matrix.hdf}} + + steps: + + - uses: actions/checkout@v4 + with: + submodules: 'recursive' + + - name: Setup MPI + uses: mpi4py/setup-mpi@v1 + with: + mpi: 'intelmpi' + + - name: Setup intel fortran + uses: fortran-lang/setup-fortran@v1 + id: setup-fortran + with: + compiler: intel-classic + version: '2021.10' + + - name: CMake build + run: | + cmake -S . -B build \ + -DCMAKE_BUILD_TYPE=${{matrix.build-type}} \ + -DSEMBA_FDTD_ENABLE_MPI=${{matrix.mpi}} \ + -DSEMBA_FDTD_ENABLE_HDF=${{matrix.hdf}} \ + -DSEMBA_FDTD_ENABLE_MTLN=${{matrix.mtln}} + cmake --build build -j + + - name: Run fdtd unit tests + timeout-minutes: 60 + run: | + build/bin/fdtd_tests + + - name: Install python wrapper requirements + run: | + python -m pip install -r requirements.txt + + - name: Run all wrapper tests + if: matrix.mtln=='Yes' + run: python -m pytest test/ + + - name: Run non-mtln wrapper tests + if: matrix.mtln=='No' + run: python -m pytest -m 'not mtln' test/ \ No newline at end of file diff --git a/.github/workflows/ubuntu-intelLLVM.yml b/.github/workflows/ubuntu-intelLLVM.yml new file mode 100644 index 00000000..8be863dd --- /dev/null +++ b/.github/workflows/ubuntu-intelLLVM.yml @@ -0,0 +1,68 @@ +name: ubuntu-intelLLVM + +on: + + pull_request: + branches: + - main + - dev + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +jobs: + + builds-and-tests: + runs-on: ubuntu-latest + strategy: + matrix: + build-type: ["Debug", "Release"] + mpi: ["No", "Yes"] + mtln: ["Yes"] + hdf: ["Yes"] + + name: ${{matrix.build-type}}- mpi ${{matrix.mpi}} - mtln ${{matrix.mtln}} - hdf ${{matrix.hdf}} + + steps: + + - uses: actions/checkout@v4 + with: + submodules: 'recursive' + + - name: Setup MPI + uses: mpi4py/setup-mpi@v1 + with: + mpi: 'intelmpi' + + - name: Setup intel fortran + uses: fortran-lang/setup-fortran@v1 + id: setup-fortran + with: + compiler: intel + version: '2024.2' + + - name: CMake build + run: | + cmake -S . -B build \ + -DCMAKE_BUILD_TYPE=${{matrix.build-type}} \ + -DSEMBA_FDTD_ENABLE_MPI=${{matrix.mpi}} \ + -DSEMBA_FDTD_ENABLE_HDF=${{matrix.hdf}} \ + -DSEMBA_FDTD_ENABLE_MTLN=${{matrix.mtln}} + cmake --build build -j + + - name: Run fdtd unit tests + timeout-minutes: 60 + run: | + build/bin/fdtd_tests + + - name: Install python wrapper requirements + run: | + python -m pip install -r requirements.txt + + - name: Run wrapper tests + timeout-minutes: 60 + run: | + python -m pytest test + + diff --git a/.github/workflows/ubuntu-nvidia.yml b/.github/workflows/ubuntu-nvidia.yml new file mode 100644 index 00000000..f85802f1 --- /dev/null +++ b/.github/workflows/ubuntu-nvidia.yml @@ -0,0 +1,66 @@ +name: ubuntu-nvhpc + +on: + pull_request: + branches: + - main + - dev + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +jobs: + builds-and-test: + runs-on: ubuntu-latest + + strategy: + matrix: + build-type: ["Debug", "Release"] + mpi: ["No"] + mtln: ["No"] + hdf: ["No"] + + name: ${{matrix.build-type}}- mpi ${{matrix.mpi}} - mtln ${{matrix.mtln}} - hdf ${{matrix.hdf}} + + timeout-minutes: 30 + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + submodules: 'recursive' + + - uses: fortran-lang/setup-fortran@v1 + id: setup-fortran + with: + compiler: nvidia-hpc + version: '24.5' + + - name: Install required packages + run: | + sudo apt update + sudo apt install libhdf5-dev libopenmpi-dev + + - name: Build application + run: | + cmake -S . -B build \ + -DCMAKE_BUILD_TYPE=${{matrix.build-type}} \ + -DSEMBA_FDTD_ENABLE_MPI=${{matrix.mpi}} \ + -DSEMBA_FDTD_ENABLE_HDF=${{matrix.hdf}} \ + -DSEMBA_FDTD_ENABLE_MTLN=${{matrix.mtln}} + cmake --build build -j + + - name: Run fdtd unit tests + timeout-minutes: 30 + run: | + build/bin/fdtd_tests + + - name: Install python wrapper requirements + run: | + python -m pip install -r requirements.txt + + - name: Run non-mtln and non-hdf wrapper tests + if: matrix.mtln=='No' || matrix.hdf=='No' + run: python -m pytest -m 'not mtln and not hdf5' test/ + + \ No newline at end of file diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml deleted file mode 100644 index 752455fe..00000000 --- a/.github/workflows/ubuntu.yml +++ /dev/null @@ -1,93 +0,0 @@ -name: ubuntu - -on: - pull_request: - branches: - - main - - dev - -concurrency: - group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} - cancel-in-progress: true - -jobs: - - builds-and-test: - runs-on: ubuntu-latest - strategy: - matrix: - compiler: [ - {name: 'intel', version: '2024.2'}, - {name: 'gcc', version: 11} - ] - build-type: ["Debug", "Release"] - mpi: ["Yes", "No"] - mtln: ["Yes"] - hdf: ["Yes"] - - include: - - compiler: {name: 'intel-classic', version: '2021.10'} - build-type: "Release" - mpi: "No" - mtln: "No" - hdf: "Yes" - - compiler: {name: 'nvidia-hpc', version: '24.5'} - build-type: "Release" - mpi: "No" - mtln: "No" - hdf: "No" - - - fail-fast: false - - name: ${{matrix.compiler.name}}-${{matrix.build-type}}-mpi(${{matrix.mpi}})-mtln(${{matrix.mtln}})-hdf(${{matrix.hdf}}) - - steps: - - name: Checkout - uses: actions/checkout@v4 - with: - submodules: 'recursive' - - - - name: Install python wrapper requirements - run: python -m pip install -r requirements.txt - - - name: Setup MPI - if: matrix.mpi=='Yes' && matrix.compiler.name=='intel' - uses: mpi4py/setup-mpi@v1 - with: - mpi: 'intelmpi' - - - name: Install gcc required packages - if: matrix.compiler.name=='gcc' - run: | - sudo apt update - sudo apt install libhdf5-dev libopenmpi-dev - - - name: Setup fortran compiler - uses: fortran-lang/setup-fortran@v1 - id: setup-fortran - with: - compiler: ${{matrix.compiler.name}} - version: ${{matrix.compiler.version}} - - - name: Build application - run: | - cmake -S . -B build \ - -DCMAKE_BUILD_TYPE=${{matrix.build-type}} \ - -DSEMBA_FDTD_ENABLE_MPI=${{matrix.mpi}} \ - -DSEMBA_FDTD_ENABLE_HDF=${{matrix.hdf}} \ - -DSEMBA_FDTD_ENABLE_MTLN=${{matrix.mtln}} - cmake --build build -j - - - name: Run unit tests - run: build/bin/fdtd_tests - - - name: Run python tests - env: - SEMBA_FDTD_ENABLE_MTLN: ${{ matrix.mtln }} - SEMBA_FDTD_ENABLE_HDF: ${{ matrix.hdf }} - run: python -m pytest test/ - - - diff --git a/.github/workflows/windows-intelLLVM.yml b/.github/workflows/windows-intelLLVM.yml index b174a60d..ad966f49 100644 --- a/.github/workflows/windows-intelLLVM.yml +++ b/.github/workflows/windows-intelLLVM.yml @@ -16,33 +16,25 @@ jobs: builds-and-tests: runs-on: windows-latest strategy: - matrix: - compiler: [ {name: 'intel', version: '2024.0'} ] + matrix: build-type: ["Debug", "Release"] mpi: ["No"] mtln: ["Yes"] hdf: ["Yes"] include: - - compiler: {name: 'intel', version: '2024.0'} - build-type: "Release" + - build-type: "Release" mpi: "No" mtln: "No" hdf: "Yes" - fail-fast: false - - name: ${{matrix.build-type}}-mpi(${{matrix.mpi}})-mtln(${{matrix.mtln}})-hdf(${{matrix.hdf}}) + name: windows-intelLLVM ${{matrix.build-type}} - mpi ${{matrix.mpi}} - mtln ${{matrix.mtln}} steps: - uses: actions/checkout@v4 with: submodules: 'recursive' - - - name: Install python wrapper requirements - run: | - python -m pip install -r requirements.txt - name: Setup MPI uses: mpi4py/setup-mpi@v1 @@ -53,8 +45,8 @@ jobs: uses: fortran-lang/setup-fortran@v1 id: setup-fortran with: - compiler: ${{ matrix.compiler.name }} - version: ${{ matrix.compiler.version }} + compiler: intel + version: '2024.0' - name: Setup ninja uses: seanmiddleditch/gha-setup-ninja@master @@ -68,13 +60,15 @@ jobs: -DSEMBA_FDTD_ENABLE_HDF=${{matrix.hdf}} \ -DSEMBA_FDTD_ENABLE_MTLN=${{matrix.mtln}} cmake --build build -j + + - name: Install python wrapper requirements + run: | + python -m pip install -r requirements.txt - - name: Run unit tests - run: build/bin/fdtd_tests.exe - - - name: Run python tests (except codemodel) - env: - SEMBA_FDTD_ENABLE_MTLN: ${{ matrix.mtln }} - SEMBA_FDTD_ENABLE_HDF: ${{ matrix.hdf }} + - name: Run all wrapper tests (except codemodel) + if: matrix.mtln=='Yes' run: python -m pytest -m 'not codemodel' test/ - \ No newline at end of file + + - name: Run non-mtln wrapper tests + if: matrix.mtln=='No' + run: python -m pytest -m 'not mtln' test/ \ No newline at end of file diff --git a/doc/smbjson.md b/doc/smbjson.md index c5d874e1..557f6b22 100644 --- a/doc/smbjson.md +++ b/doc/smbjson.md @@ -244,7 +244,7 @@ This entry is an array formed by all the physical models contained in the simula ### Bulk materials -### `pec` and `pmc` +#### `pec` and `pmc` These materials represent a perfectly electrically conducting (`pec`) and perfectly magnetically conducting (`pmc`). @@ -254,7 +254,7 @@ These materials represent a perfectly electrically conducting (`pec`) and perfec "materials": [ {"id": 1, "type": "pec"} ] ``` -### `isotropic` +#### `isotropic` A `material` with `type` `isotropic` represents an isotropic material with constant (not frequency dependent) relative permittivity $\varepsilon_r$, relative permeability $\mu_r$, electric conductivity $\sigma$ and/or magnetic conductivity $\sigma_m$: @@ -275,10 +275,13 @@ A `material` with `type` `isotropic` represents an isotropic material with const } ``` -### `multilayeredSurface` +### Surface materials + +In surface materials, `elementIds` must reference `cell` elements. All `intervals` modeling entities different to oriented surfaces are ignored. + +#### `multilayeredSurface` A `multilayeredSurface` must contain the entry `` which is an array indicating materials which are described in the same way as [isotropic materials](#isotropic) and a ``. -Its `elementIds` must reference `cell` elements. All `intervals` modeling entities different to oriented surfaces are ignored. ```json { @@ -293,7 +296,11 @@ Its `elementIds` must reference `cell` elements. All `intervals` modeling entiti } ``` -### `thinSlot` +### Line materials + +In line materials, `elementIds` must reference `cell` elements. All `intervals` modeling entities different to lines are ignored. + +#### `thinSlot` A `thinSlot` represents a gap between two conductive surfaces. Therefore it must be located at a surface and be defined using line cell elements only. Its `` is a real number which defines the distance between the surfaces in meters. @@ -306,7 +313,9 @@ A `thinSlot` represents a gap between two conductive surfaces. Therefore it must } ``` -### `wire` +### Cable materials + +#### `wire` A `wire`, or *thin wire*, represents an electrically conducting wire-like structure with a radius much smaller than the surrounding cell sizes. These structures are solved by an algorithm similar to the one described in: @@ -352,13 +361,13 @@ A single wire might be surrounded by a dielectric material. In that case, the ra ``` If the `dielectric` field is present but any of `radius` or `relativePermittivity` is absent, the parsing of the dielectric will fail. -### `multiwire` +#### `multiwire` A `multiwire`, models $N+1$ electrical wires inside a bundled. The voltages and currents on these wires are solved by a multiconductor transmission lines (MTLN) solver described in: Paul, C. R. (2007). Analysis of multiconductor transmission lines. John Wiley & Sons. -`multiwire` materials are assumed to be contained within a `wire` or another `multiwire` which is the external domain and is used as voltage reference. +`multiwire` materials are assumed to be contained within a `wire` or another `multiwire` (see the [cable](#cable) `materialAssociation`) which is the external domain and is used as voltage reference. They must contain the following entries: + `` and `` which must be matrices with a size $N \times N$. @@ -374,6 +383,7 @@ If the number of wires of the `multiwire` is equal to 1, none of the properties + `[resistiveTerm]` defined by a real representing transfer impedance resistance. Defaults to `0.0` + `[inductiveTerm]` defined by a real representing transfer impedance inductance. Defaults to `0.0`. ++ `[pole-residues]` TODO REVIEW + `[direction]` which can be `both`, `inwards`, or `outwards`. Indicating the type of coupling considered. Defaults to `both` meaning that fields can couple from the exterior to interior and the other way round. **Example:** @@ -399,7 +409,7 @@ If the number of wires of the `multiwire` is equal to 1, none of the properties } ``` -### `terminal` +#### `terminal` A `terminal` models a lumped circuit which is assumed to located at one end of a `wire` or `multiwire`. Terminals are assumed to be assigned on points and therefore have zero dimension. @@ -430,7 +440,7 @@ There is an optional key which is needed in case the termination is attached to "termination": [ {"type": "series", "resistance": 50.0} ] } ``` -#### `SPICE terminations` +##### `SPICE terminations` As with the rest of terminations, SPICE terminations have to be equivalents to 2-port networks, i.e, the model in `file` can be composed of an arbitrary number of components, but it must have only two external nodes. @@ -447,7 +457,7 @@ As with the rest of terminations, SPICE terminations have to be equivalents to 2 `ListOfComponents.lib` is a file where one or more SPICE subcircuits are defined. The file does not need to contain only the subcircuit that is going to be used in the termination. The particular subcircuit among those defined in the file is selected using the key `name`. -### `connector` +#### `connector` The `connector` represents the physical connection of a bundle to a structure. `connector` assigns properties to the initial or last segment of a `wire` or a `multiwire`. This `wire` can be either a single wire or the outermost conductor of a `cable` bundle. The `conector` can have the following properties: @@ -479,18 +489,42 @@ This entry stores associations between `materials` and `elements` using their re + ``: A single integer indicating the `id` of a material which must be present in the `materials` list. + ``: A list of `id`s of the elements to which this material will be associated. ++ ``: can be `bulk`, `surface`, or `cable`; described below. +### `bulk` -Material associations with bulk or surface materials such as `pec`, `pmc` or `isotropic` can be assigned to one or many elements of type `cell`. If the `cell` contains `intervals` representing points, these will be ignored. +Bulk materials such as `pec`, `pmc` or `isotropic` can be assigned to one or many elements of type `cell`. If the `cell` contains `intervals` representing points, these will be ignored. ```json "materialAssociations": [ - {"materialId": 1, "elementIds": [2]}, - {"materialId": 1, "elementIds": [3]} + {"type": "bulk", "materialId": 1, "elementIds": [2]}, + {"type": "bulk", "materialId": 1, "elementIds": [3]} ] ``` -Associations with cables can contain the following inputs: +### `surface` + +Surface materials can only be assigned to elements of type `cell`. If the `cell` contains `intervals` representing entities different to oriented surfaces these will be ignored. + +```json +"materialAssociations": [ + {"type": "surface", "materialId": 1, "elementIds": [2]} +] +``` + +### `line` + +Line materials can only be assigned to elements of type `cell`. If the `cell` contains `intervals` representing entities different to segments these will be ignored. + +```json +"materialAssociations": [ + {"type": "line", "materialId": 2, "elementIds": [4]} +] +``` + +### `cable` + +This object establishes the relationship between the physical models described in a `material` and parts of the geometry. Besides a `type`, `materialId` and `elementIds`; a `cable` can contain the following inputs: + `` and `` which must be present within the `materials` list of type. These entries indicate the lumped circuits connected at the ends of the cable. + `[initialConnectorId]` and `[endConnectorId]` entries which must point to materials of type `connector` and are assigned to the last segments of the corresponding ends of the cable. @@ -501,6 +535,7 @@ Associations with cables can contain the following inputs: ```json { "name": "line_0_0", + "type": "cable", "elementIds": [ 1 ], "materialId": 10, "initialTerminalId": 20, diff --git a/pytest.ini b/pytest.ini index 7c5346e7..098efa49 100644 --- a/pytest.ini +++ b/pytest.ini @@ -2,4 +2,4 @@ markers = mtln: tests which use mtln features. codemodel: test that need xspice codemodels. - hdf: tests that need hdf5. \ No newline at end of file + hdf5: tests that need hdf5. \ No newline at end of file diff --git a/src_json_parser/mesh.F90 b/src_json_parser/mesh.F90 index 182e2615..6213ef77 100644 --- a/src_json_parser/mesh.F90 +++ b/src_json_parser/mesh.F90 @@ -53,7 +53,7 @@ module mesh_mod procedure :: polylineToLinels => mesh_polylineToLinels procedure :: nodeToPixel => mesh_nodeToPixel - procedure :: printHashInfo => mesh_printHashInfo + procedure :: printCoordHashInfo => mesh_printCoordHashInfo procedure :: allocateCoordinates => mesh_allocateCoordinates procedure :: allocateElements => mesh_allocateElements end type @@ -75,23 +75,15 @@ subroutine mesh_allocateElements(this, buck) end subroutine - subroutine mesh_printHashInfo(this) + subroutine mesh_printCoordHashInfo(this) class(mesh_t) :: this integer :: num_buckets, num_items, num_collisions, max_depth - - write(*,*) 'Coordinates hash info:' call this%coordinates%stats(num_buckets,num_items,num_collisions,max_depth) write(*,'(A,T40,I0)') ' Number of buckets allocated: ',num_buckets write(*,'(A,T40,I0)') ' Number of key-value pairs stored: ',num_items write(*,'(A,T40,I0)') ' Total number of hash-collisions: ',num_collisions write(*,'(A,T40,I0)') ' The worst case bucket depth is ',max_depth - - write(*,*) 'Elements hash info:' - call this%elements%stats(num_buckets,num_items,num_collisions,max_depth) - write(*,'(A,T40,I0)') ' Number of buckets allocated: ',num_buckets - write(*,'(A,T40,I0)') ' Number of key-value pairs stored: ',num_items - write(*,'(A,T40,I0)') ' Total number of hash-collisions: ',num_collisions - write(*,'(A,T40,I0)') ' The worst case bucket depth is ',max_depth + print * end subroutine @@ -145,7 +137,7 @@ function mesh_getCoordinate(this, id, found) result(res) if (stat /= 0) return select type(d) - type is (coordinate_t) + type is (coordinate_t) res = d if (present(found)) found = .true. end select @@ -165,7 +157,7 @@ function mesh_getNode(this, id, found) result(res) if (status /= 0) return select type(d) - type is (node_t) + type is (node_t) res = d if (present(found)) found = .true. end select @@ -185,7 +177,7 @@ function mesh_getPolyline(this, id, found) result(res) if (stat /= 0) return select type(d) - type is (polyline_t) + type is (polyline_t) res = d if (present(found)) found = .true. end select @@ -205,7 +197,7 @@ function mesh_getCellRegion(this, id, found) result (res) if (stat /= 0) return select type(d) - type is (cell_region_t) + type is (cell_region_t) res = d if (present(found)) found = .true. end select @@ -226,7 +218,7 @@ function mesh_getCellRegions(this, ids) result (res) do i = 1, size(ids) cR = this%getCellRegion(ids(i), found) if (found) then - numberOfCellRegions = numberOfCellRegions + 1 + numberOfCellRegions = numberOfCellRegions + 1 end if end do @@ -235,8 +227,8 @@ function mesh_getCellRegions(this, ids) result (res) do i = 1, size(ids) cR = this%getCellRegion(ids(i), found) if (found) then - res(j) = cR - j = j + 1 + res(j) = cR + j = j + 1 end if end do diff --git a/src_json_parser/smbjson.F90 b/src_json_parser/smbjson.F90 index 6421815e..06efd64d 100644 --- a/src_json_parser/smbjson.F90 +++ b/src_json_parser/smbjson.F90 @@ -29,7 +29,6 @@ module smbjson type(json_value), pointer :: root => null() type(mesh_t) :: mesh type(IdChildTable_t) :: matTable, elementTable - logical, public :: isInitialized = .false. contains procedure :: readProblemDescription @@ -92,17 +91,10 @@ module smbjson end type type, private :: materialAssociation_t - ! Common fields character(:), allocatable :: name integer :: materialId integer, dimension(:), allocatable :: elementIds character(:), allocatable :: matAssType - ! Cable specific fields. - integer :: initialTerminalId = -1 - integer :: endTerminalId = -1 - integer :: initialConnectorId = -1 - integer :: endConnectorId = -1 - integer :: containedWithinElementId = -1 end type type, private :: domain_t @@ -135,8 +127,6 @@ function parser_ctor(filename) result(res) allocate(res%core) call res%jsonfile%get_core(res%core) call res%jsonfile%get('.', res%root) - - res%isInitialized = .true. end function function readProblemDescription(this) result (res) @@ -451,15 +441,16 @@ function buildPECPMCRegions(this, matType) result(res) class(parser_t) :: this character (len=*), intent(in) :: matType type(PECRegions) :: res - type(materialAssociation_t), dimension(:), allocatable :: mAs + type(json_value_ptr), dimension(:), allocatable :: mAPtrs + type(materialAssociation_t) :: mA type(coords), dimension(:), pointer :: cs integer :: i - mAs = this%getMaterialAssociations([matType]) + mAPtrs = this%getMaterialAssociations(J_MAT_ASS_TYPE_BULK, matType) block type(coords), dimension(:), pointer :: emptyCoords - if (size(mAs) == 0) then + if (size(mAPtrs) == 0) then allocate(emptyCoords(0)) call appendRegion(res%lins, res%nLins, res%nLins_max, emptyCoords) call appendRegion(res%surfs, res%nSurfs, res%nSurfs_max, emptyCoords) @@ -468,12 +459,13 @@ function buildPECPMCRegions(this, matType) result(res) end if end block - do i = 1, size(mAs) - call this%matAssToCoords(cs, mAs(i), CELL_TYPE_LINEL) + do i = 1, size(mAPtrs) + mA = this%parseMaterialAssociation(mAptrs(i)%p) + call this%matAssToCoords(cs, mA, CELL_TYPE_LINEL) call appendRegion(res%lins, res%nLins, res%nLins_max, cs) - call this%matAssToCoords(cs, mAs(i), CELL_TYPE_SURFEL) + call this%matAssToCoords(cs, mA, CELL_TYPE_SURFEL) call appendRegion(res%surfs, res%nSurfs, res%nSurfs_max, cs) - call this%matAssToCoords(cs, mAs(i), CELL_TYPE_VOXEL) + call this%matAssToCoords(cs, mA, CELL_TYPE_VOXEL) call appendRegion(res%vols, res%nVols, res%nVols_max, cs) deallocate(cs) end do @@ -484,30 +476,20 @@ subroutine appendRegion(resCoords, resNCoords, resNCoordsMax, cs) integer, intent(out) :: resNCoords, resNCoordsMax type(coords), dimension(:), pointer, intent(in) :: cs type(coords) , dimension(:), allocatable :: auxCs - integer :: i if (.not. associated(resCoords)) then allocate(resCoords(size(cs))) - do i = 1, size(cs) ! Use do loop to prevent stack overflow in large cs - resCoords(i) = cs(i) - end do + resCoords(:) = cs(:) resNCoords = size(cs) resNCoordsMax = size(cs) else - do i = 1, size(resCoords) - auxCs(i) = resCoords(i) - end do + auxCs(:) = resCoords(:) deallocate(resCoords) - - allocate(resCoords(size(auxCs) + size(cs))) - resNCoords = size(resCoords) - resNCoordsMax = size(resCoords) - do i = 1, size(auxCs) - resCoords(i) = auxCs(i) - end do - do i = 1, size(cs) - resCoords(i + size(auxCs)) = cs(i) - end do + allocate(resCoords(resNCoords + size(cs))) + resCoords(1:resNCoords) = auxCs + resCoords(resNCoords+1 : resNCoords+size(cs)) = cs(:) + resNCoords = resNCoords + size(cs) + resNCoordsMax = resNCoordsMax + size(cs) end if end subroutine end function @@ -515,7 +497,8 @@ subroutine appendRegion(resCoords, resNCoords, resNCoordsMax, cs) function readDielectricRegions(this) result (res) class(parser_t), intent(in) :: this type(DielectricRegions) :: res - + type(json_value_ptr), dimension(:), allocatable :: matAssPtrs + call fillDielectricsOfCellType(res%vols, CELL_TYPE_VOXEL) call fillDielectricsOfCellType(res%surfs, CELL_TYPE_SURFEL) call fillDielectricsOfCellType(res%lins, CELL_TYPE_LINEL) @@ -532,23 +515,23 @@ subroutine fillDielectricsOfCellType(res, cellType) integer, intent(in) :: cellType type(dielectric_t), dimension(:), pointer :: res - type(materialAssociation_t), dimension(:), allocatable :: mAs + type(json_value_ptr), dimension(:), allocatable :: mAPtrs type(materialAssociation_t) :: mA type(cell_region_t) :: cR integer :: i, j integer :: nCs, nDielectrics - mAs = this%getMaterialAssociations([J_MAT_TYPE_ISOTROPIC]) - if (size(mAs) == 0) then + mAPtrs = this%getMaterialAssociations(J_MAT_ASS_TYPE_BULK, J_MAT_TYPE_ISOTROPIC) + if (size(mAPtrs) == 0) then allocate(res(0)) return end if ! Precounts nDielectrics = 0 - do i = 1, size(mAs) - if (containsCellRegionsWithType(mAs(i), cellType)) then + do i = 1, size(mAPtrs) + if (containsCellRegionsWithType(mAPtrs(i)%p, cellType)) then nDielectrics = nDielectrics + 1 end if end do @@ -559,42 +542,45 @@ subroutine fillDielectricsOfCellType(res, cellType) if (nDielectrics == 0) return j = 0 - do i = 1, size(mAs) - if (.not. containsCellRegionsWithType(mAs(i), cellType)) cycle + do i = 1, size(mAPtrs) + if (.not. containsCellRegionsWithType(mAPtrs(i)%p, cellType)) cycle j = j + 1 - res(j) = readDielectric(mAs(i), cellType) + res(j) = readDielectric(mAPtrs(i)%p, cellType) end do end subroutine - function readDielectric(mA, cellType) result(res) - type(materialAssociation_t), intent(in) :: mA + function readDielectric(mAPtr, cellType) result(res) + type(json_value), pointer, intent(in) :: mAPtr integer, intent(in) :: cellType type(Dielectric_t) :: res + type(materialAssociation_t) :: mA type(cell_region_t) :: cR type (coords), dimension(:), allocatable :: coords - type(json_value_ptr) :: matPtr + integer :: e, j + mA = this%parseMaterialAssociation(mAPtr) allocate(res%c1P(0)) res%n_c1p = 0 call this%matAssToCoords(res%c2p, mA, cellType) res%n_c2p = size(res%c2p) - matPtr = this%matTable%getId(mA%materialId) ! Fills rest of dielectric data. - res%sigma = this%getRealAt(matPtr%p, J_MAT_ELECTRIC_CONDUCTIVITY, default=0.0) - res%sigmam = this%getRealAt(matPtr%p, J_MAT_MAGNETIC_CONDUCTIVITY, default=0.0) - res%eps = this%getRealAt(matPtr%p, J_MAT_REL_PERMITTIVITY, default=1.0)*EPSILON_VACUUM - res%mu = this%getRealAt(matPtr%p, J_MAT_REL_PERMEABILITY, default=1.0)*MU_VACUUM + res%sigma = this%getRealAt(mAPtr, J_MAT_ELECTRIC_CONDUCTIVITY, default=0.0) + res%sigmam = this%getRealAt(mAPtr, J_MAT_MAGNETIC_CONDUCTIVITY, default=0.0) + res%eps = this%getRealAt(mAPtr, J_MAT_REL_PERMITTIVITY, default=1.0)*EPSILON_VACUUM + res%mu = this%getRealAt(mAPtr, J_MAT_REL_PERMEABILITY, default=1.0)*MU_VACUUM end function - logical function containsCellRegionsWithType(mA, cellType) + logical function containsCellRegionsWithType(mAPtr, cellType) integer, intent(in) :: cellType - type(materialAssociation_t), intent(in) :: mA + type(json_value), pointer, intent(in) :: mAPtr + type(materialAssociation_t) :: mA integer :: e type(cell_region_t) :: cR + mA = this%parseMaterialAssociation(mAPtr) do e = 1, size(mA%elementIds) cR = this%mesh%getCellRegion(mA%elementIds(e)) if (size(cellRegionToCoords(cR, cellType)) /= 0) then @@ -622,8 +608,7 @@ subroutine matAssToCoords(this, res, mA, cellType) nCs = 0 do e = 1, size(mA%elementIds) cR = this%mesh%getCellRegion(mA%elementIds(e)) - newCoords = cellRegionToCoords(cR, cellType) - nCs = nCs + size(newCoords) + nCs = nCs + size(cellRegionToCoords(cR, cellType)) end do ! Fills coords @@ -643,19 +628,21 @@ subroutine matAssToCoords(this, res, mA, cellType) function readLossyThinSurfaces(this) result (res) class(parser_t), intent(in) :: this type(LossyThinSurfaces) :: res - type(materialAssociation_t), dimension(:), allocatable :: mAs + type(json_value_ptr), dimension(:), allocatable :: matAssPtrs type(json_value_ptr) :: mat integer :: nLossySurfaces logical :: found integer :: i, j, k + type(materialAssociation_t) :: mA type(coords), dimension(:), pointer :: cs - - mAs = this%getMaterialAssociations([J_MAT_TYPE_MULTILAYERED_SURFACE]) + matAssPtrs = this%getMaterialAssociations(& + J_MAT_ASS_TYPE_SURFACE, J_MAT_TYPE_MULTILAYERED_SURFACE) ! Precounts nLossySurfaces = 0 - do i = 1, size(mAs) - call this%matAssToCoords(cs, mAs(i), CELL_TYPE_SURFEL) + do i = 1, size(matAssPtrs) + mA = this%parseMaterialAssociation(matAssPtrs(i)%p) + call this%matAssToCoords(cs, mA, CELL_TYPE_SURFEL) if (size(cs) > 0) nLossySurfaces = nLossySurfaces + 1 end do @@ -670,10 +657,11 @@ function readLossyThinSurfaces(this) result (res) res%length_max = nLossySurfaces res%nC_max = nLossySurfaces k = 1 - do i = 1, size(mAs) - call this%matAssToCoords(cs, mAs(i), CELL_TYPE_SURFEL) + do i = 1, size(matAssPtrs) + mA = this%parseMaterialAssociation(matAssPtrs(i)%p) + call this%matAssToCoords(cs, mA, CELL_TYPE_SURFEL) if (size(cs) == 0) cycle - res%cs(k) = readLossyThinSurface(mAs(i)) + res%cs(k) = readLossyThinSurface(mA) k = k + 1 end do @@ -1391,28 +1379,31 @@ function readThinSlots(this) result (res) class(parser_t) :: this type(ThinSlots) :: res - type(materialAssociation_t), dimension(:), allocatable :: mAs + type(json_value_ptr), dimension(:), allocatable :: mAPtrs integer :: i - mAs = this%getMaterialAssociations([J_MAT_TYPE_SLOT]) - if (size(mAs) == 0) then + mAPtrs = this%getMaterialAssociations(J_MAT_ASS_TYPE_LINE, J_MAT_TYPE_SLOT) + if (size(mAPtrs) == 0) then allocate(res%tg(0)) return end if - res%n_tg = size(mAs) + res%n_tg = size(mAPtrs) allocate(res%tg(res%n_tg)) - do i = 1, size(mAs) - res%tg = readThinSlot(mAs(i)) + do i = 1, size(mAPtrs) + res%tg = readThinSlot(mAPtrs(i)%p) end do contains - function readThinSlot(mA) result(res) - type (materialAssociation_t), intent(in) :: mA + function readThinSlot(mAPtr) result(res) + type (json_value), pointer, intent(in) :: mAPtr type (thinSlot) :: res + type (materialAssociation_t) :: mA type (coords), dimension(:), pointer :: cs type(json_value_ptr) :: mat logical :: found + mA = this%parseMaterialAssociation(mAPtr) + mat = this%matTable%getId(mA%materialId) res%width = this%getRealAt(mat%p, J_MAT_THINSLOT_WIDTH, found) if (.not. found) then @@ -1482,19 +1473,28 @@ function buildBaseThinSlotComponent(cs) result(res) function readThinWires(this) result (res) class(parser_t) :: this type(ThinWires) :: res - type(materialAssociation_t), dimension(:), allocatable :: mAs + type(json_value), pointer :: cable, matAss + type(json_value_ptr), dimension(:), allocatable :: cables integer :: i, j logical :: found - mAs = this%getMaterialAssociations([J_MAT_TYPE_WIRE]) + call this%core%get(this%root, J_MATERIAL_ASSOCIATIONS, matAss, found) + if (.not. found) then + allocate(res%tw(0)) + res%n_tw = 0 + res%n_tw_max = 0 + return + end if + + cables = this%jsonValueFilterByKeyValue(matAss, J_TYPE, J_MAT_ASS_TYPE_CABLE) ! Pre-allocates thin wires. block integer :: nTw nTw = 0 - if (size(mAs) /=0 ) then - do i = 1, size(mAs) - if (isThinWire(mAs(i))) nTw = nTw+1 + if (size(cables) /=0 ) then + do i = 1, size(cables) + if (isThinWire(cables(i)%p)) nTw = nTw+1 end do end if @@ -1504,19 +1504,21 @@ function readThinWires(this) result (res) end block j = 1 - if (size(mAs) /=0 ) then - do i = 1, size(mAs) - if (isThinWire(mAs(i))) then - res%tw(j) = readThinWire(mAs(i)) + if (size(cables) /=0 ) then + do i = 1, size(cables) + if (isThinWire(cables(i)%p)) then + res%tw(j) = readThinWire(cables(i)%p) j = j+1 end if end do end if + + contains function readThinWire(cable) result(res) type(ThinWire) :: res - type(materialAssociation_t), intent(in) :: cable + type(json_value), pointer, intent(in) :: cable character (len=:), allocatable :: entry type(json_value), pointer :: je, je2 @@ -1525,7 +1527,8 @@ function readThinWire(cable) result(res) real :: radius, resistance, inductance block type(json_value_ptr) :: m - m = this%matTable%getId(cable%materialId) + m = this%matTable%getId(this%getIntAt(cable, J_MATERIAL_ID, found)) + if (.not. found) write(error_unit, *) "ERROR: material id not found in mat. association." call this%core%get(m%p, J_MAT_WIRE_RADIUS, radius, default = 0.0) call this%core%get(m%p, J_MAT_WIRE_RESISTANCE, resistance, default = 0.0) call this%core%get(m%p, J_MAT_WIRE_INDUCTANCE, inductance, default = 0.0) @@ -1539,7 +1542,7 @@ function readThinWire(cable) result(res) type(json_value_ptr) :: terminal type(thinwiretermination_t) :: term character (len=:), allocatable :: label - terminal = this%matTable%getId(cable%initialTerminalId) + terminal = this%matTable%getId(this%getIntAt(cable, J_MAT_ASS_CAB_INI_TERM_ID)) term = readThinWireTermination(terminal%p) res%tl = term%terminationType res%R_LeftEnd = term%r @@ -1551,7 +1554,7 @@ function readThinWire(cable) result(res) block type(json_value_ptr) :: terminal type(thinwiretermination_t) :: term - terminal = this%matTable%getId(cable%endTerminalId) + terminal = this%matTable%getId(this%getIntAt(cable, J_MAT_ASS_CAB_END_TERM_ID)) term = readThinWireTermination(terminal%p) res%tr = term%terminationType res%R_RightEnd = term%r @@ -1562,16 +1565,23 @@ function readThinWire(cable) result(res) block type(linel_t), dimension(:), allocatable :: linels + integer, dimension(:), allocatable :: elementIds type(polyline_t) :: polyline character (len=MAX_LINE) :: tagLabel type(generator_description_t), dimension(:), allocatable :: genDesc - - polyline = this%mesh%getPolyline(cable%elementIds(1)) + call this%core%get(cable, J_ELEMENTIDS, elementIds, found) + if (.not. found) then + write(error_unit, *) "elementIds not found for material association." + end if + if (size(elementIds) /= 1) then + write(error_unit, *) "Thin wires must be defined by a single polyline element." + end if + polyline = this%mesh%getPolyline(elementIds(1)) linels = this%mesh%polylineToLinels(polyline) - write(tagLabel, '(i10)') cable%elementIds(1) + write(tagLabel, '(i10)') elementIds(1) - genDesc = readGeneratorOnThinWire(linels, cable%elementIds) + genDesc = readGeneratorOnThinWire(linels, elementIds) res%n_twc = size(linels) res%n_twc_max = size(linels) @@ -1721,22 +1731,35 @@ function strToTerminationType(label) result(res) end select end function - logical function isThinWire(mA) - type(materialAssociation_t) :: mA + logical function isThinWire(cable) + type(json_value), pointer :: cable type(json_value_ptr) :: mat - type(polyline_t) :: pl + integer, dimension(:), allocatable :: eIds logical :: found isThinWire = .false. - if (size(mA%elementIds) /= 1) then - write(error_unit, *) "ERROR: Thin wires must be defined by a single element id." - end if + mat = this%matTable%getId(this%getIntAt(cable, J_MATERIAL_ID, found=found)) + if (.not. found) return + if (this%getStrAt(mat%p, J_TYPE) /= J_MAT_TYPE_WIRE) return + + mat = this%matTable%getId(this%getIntAt(cable, J_MAT_ASS_CAB_INI_TERM_ID, found=found)) + if (.not. found) return + if (this%getStrAt(mat%p, J_TYPE) /= J_MAT_TYPE_TERMINAL) return + + mat = this%matTable%getId(this%getIntAt(cable, J_MAT_ASS_CAB_END_TERM_ID, found=found)) + if (.not. found) return + if (this%getStrAt(mat%p, J_TYPE) /= J_MAT_TYPE_TERMINAL) return + + eIds = this%getIntsAt(cable, J_ELEMENTIDS, found=found) + if (.not. found) return + if (size(eIds) /= 1) return + + block + type(polyline_t) :: pl + pl = this%mesh%getPolyline(eIds(1)) + if (.not. this%mesh%arePolylineSegmentsStructured(pl)) return + end block - pl = this%mesh%getPolyline(mA%elementIds(1)) - if (.not. this%mesh%arePolylineSegmentsStructured(pl)) then - write(error_unit, *) "ERROR: Thin wires must be defined by a structured polyline." - end if - isThinWire = .true. end function end function @@ -1841,31 +1864,22 @@ function getNPDomainType(typeLabel, hasTransferFunction) result(res) function parseMaterialAssociation(this, matAss) result(res) class(parser_t) :: this type(json_value), pointer, intent(in) :: matAss - type(json_value_ptr) :: mat type(materialAssociation_t) :: res character (len=*), parameter :: errorMsgInit = "ERROR reading material association: " logical :: found - logical :: isMultiwire, isWireOrMultiwire ! Fills material association. res%materialId = this%getIntAt(matAss, J_MATERIAL_ID, found) if (.not. found) call showLabelNotFoundError(J_MATERIAL_ID) - res%elementIds = this%getIntsAt(matAss, J_ELEMENTIDS, found) if (.not. found) call showLabelNotFoundError(J_ELEMENTIDS) - + res%matAssType = this%getStrAt(matAss, J_TYPE, found) + if (.not. found) call showLabelNotFoundError(J_TYPE) res%name = this%getStrAt(matAss, J_NAME, found) if (.not. found) then res%name = "" end if - res%initialTerminalId = this%getIntAt(matAss, J_MAT_ASS_CAB_INI_TERM_ID, default=-1) - res%endTerminalId = this%getIntAt(matAss, J_MAT_ASS_CAB_END_TERM_ID, default=-1) - res%initialConnectorId = this%getIntAt(matAss, J_MAT_ASS_CAB_INI_CONN_ID, default=-1) - res%endConnectorId = this%getIntAt(matAss, J_MAT_ASS_CAB_END_CONN_ID, default=-1) - res%containedWithinElementId = & - this%getIntAt(matAss, J_MAT_ASS_CAB_CONTAINED_WITHIN_ID, default=-1) - ! Checks validity of associations. if (this%matTable%checkId(res%materialId) /= 0) then write(error_unit, *) errorMsgInit, "material with id ", res%materialId, " not found." @@ -1883,70 +1897,28 @@ function parseMaterialAssociation(this, matAss) result(res) end do end block - mat = this%matTable%getId(res%materialId) - isMultiwire = this%getStrAt(mat%p, J_TYPE) == J_MAT_TYPE_MULTIWIRE - isWireOrMultiwire = & - this%getStrAt(mat%p, J_TYPE) == J_MAT_TYPE_WIRE .or. isMultiwire - - if (isWireOrMultiwire) then - if (res%initialTerminalId == -1 .or. res%endTerminalId == -1) then - write(error_unit, *), errorMsgInit, "wire associations must include terminals." - end if - if (.not. isMaterialIdOfType(res%initialTerminalId, J_MAT_TYPE_TERMINAL)) then - write(error_unit, *) errorMsgInit, "material with id ", res%materialId, " must be a terminal." - end if - if (.not. isMaterialIdOfType(res%endTerminalId, J_MAT_TYPE_TERMINAL)) then - write(error_unit, *) errorMsgInit, "material with id ", res%materialId, " must be a terminal." - end if - if (res%initialConnectorId /= -1) then - if (.not. isMaterialIdOfType(res%initialConnectorId, J_MAT_TYPE_CONNECTOR)) then - write(error_unit, *) errorMsgInit, "material with id ", res%materialId, " must be a connector." - end if - end if - if (res%endConnectorId /= -1) then - if (.not. isMaterialIdOfType(res%endConnectorId, J_MAT_TYPE_CONNECTOR)) then - write(error_unit, *) errorMsgInit, "material with id ", res%materialId, " must be a connector." - end if - end if - end if - if (isMultiwire) then - ! Not defininign a containedWithinElementId is an error if the simulation is a 3D-FDTD one. - ! For pure MTLN mode it is not an error. - ! if (res%containedWithinElementId == -1) then - ! write(error_unit, *) errorMsgInit, "multiwire associations must include: ", J_MAT_ASS_CAB_CONTAINED_WITHIN_ID - ! end if - if (this%mesh%checkElementId(res%containedWithinElementId) /= 0) then - write(error_unit, *) errorMsgInit, "element with id ", res%containedWithinElementId, " not found." - end if - end if + ! This function does not work with material associations for cables. + ! DO NOT use it to read that. + if (res%matAssType == J_MAT_ASS_TYPE_CABLE) then + write(error_unit, *) errorMsgInit, "invalid type." + endif contains - logical function isMaterialIdOfType(matId, matType) - integer, intent(in) :: matId - character (len=*), intent(in) :: matType - type(json_value_ptr) :: mat - logical :: materialFound - if (this%matTable%checkId(matId) /= 0) then - write(error_unit, *) "Material with id ", matId, " not found." - end if - mat = this%matTable%getId(matId) - isMaterialIdOfType = this%getStrAt(mat%p, J_TYPE) == matType - end function - subroutine showLabelNotFoundError(label) character (len=*), intent(in) :: label end subroutine end function - function getMaterialAssociations(this, materialTypes) result(res) + function getMaterialAssociations(this, matAssType, materialType) result(res) class(parser_t) :: this - character(len=*), intent(in) :: materialTypes(:) - type(materialAssociation_t), dimension(:), allocatable :: res type(json_value), pointer :: allMatAss + character(len=*), intent(in) :: matAssType + character(len=*), intent(in) :: materialType + type(json_value_ptr), dimension(:), allocatable :: res - type(json_value), pointer :: mAPtr - integer :: i, j, k + type(json_value_ptr), dimension(:), allocatable :: mAPtrs + integer :: i, j integer :: nMaterials logical :: found @@ -1956,26 +1928,27 @@ function getMaterialAssociations(this, materialTypes) result(res) return end if + mAPtrs = this%jsonValueFilterByKeyValue(allMatAss, J_TYPE, matAssType) + if (size(mAPtrs) == 0) then + allocate(res(0)) + return + end if + + nMaterials = 0 - do i = 1, this%core%count(allMatAss) - call this%core%get_child(allMatAss, i, mAPtr) - do j = 1, size(materialTypes) - if (isAssociatedWithMaterial(mAPtr, trim(materialTypes(j)))) then - nMaterials = nMaterials + 1 - end if - end do + do i = 1, size(mAPtrs) + if (isAssociatedWithMaterial(mAPtrs(i)%p, materialType)) then + nMaterials = nMaterials + 1 + end if end do allocate(res(nMaterials)) j = 1 - do i = 1, this%core%count(allMatAss) - call this%core%get_child(allMatAss, i, mAPtr) - do k = 1, size(materialTypes) - if (isAssociatedWithMaterial(mAPtr, trim(materialTypes(k)))) then - res(j) = this%parseMaterialAssociation(mAPtr) - j = j+1 - end if - end do + do i = 1, size(mAPtrs) + if (isAssociatedWithMaterial(mAPtrs(i)%p, materialType)) then + res(j) = mAPtrs(i) + j = j+1 + end if end do contains @@ -2058,69 +2031,66 @@ function readMTLN(this, grid) result (mtln_res) type(Desplazamiento), intent(in) :: grid type(mtln_t) :: mtln_res type(fhash_tbl_t) :: elemIdToPosition, elemIdToCable, connIdToConnector - type(materialAssociation_t), dimension(:), allocatable :: wires, multiwires, cables + type(json_value_ptr), dimension(:), allocatable :: cables mtln_res%time_step = this%getRealAt(this%root, J_GENERAL//'.'//J_GEN_TIME_STEP) mtln_res%number_of_steps = this%getRealAt(this%root, J_GENERAL//'.'//J_GEN_NUMBER_OF_STEPS) - wires = this%getMaterialAssociations([J_MAT_TYPE_WIRE]) - multiwires = this%getMaterialAssociations([J_MAT_TYPE_MULTIWIRE]) - cables = this%getMaterialAssociations(& - [J_MAT_TYPE_WIRE//' ',& - J_MAT_TYPE_MULTIWIRE ]) - ! 5 spaces are needed to make strings have same length. - ! Why? Because of FORTRAN! It only accepts fixed length strings for arrays. + cables = readCables() mtln_res%connectors => readConnectors() call addConnIdToConnectorMap(connIdToConnector, mtln_res%connectors) - if (size(multiwires) /= 0) mtln_res%has_multiwires = .true. + if (countNumberOfMultiwires(cables) /= 0) mtln_res%has_multiwires = .true. - allocate (mtln_res%cables(size(wires) + size(multiwires))) + allocate (mtln_res%cables(countNumberOfWires(cables) + countNumberOfMultiwires(cables))) block logical :: is_read integer :: i, j, ncc type(cable_t) :: read_cable - ncc = 0 - do i = 1, size(cables) - is_read = .true. - read_cable = readMTLNCable(cables(i), is_read) - if (.not. isCableNameUnique(read_cable, mtln_res%cables, ncc)) then - error stop 'Cable name "'//read_cable%name//'" has already been used' - end if - ncc = ncc + 1 - mtln_res%cables(ncc) = read_cable - call addElemIdToCableMap(elemIdToCable, cables(i)%elementIds, ncc) - call addElemIdToPositionMap(elemIdToPosition, cables(i)%elementIds) - end do + if (size(cables) /= 0) then + ncc = 0 + do i = 1, size(cables) + if (isWire(cables(i)%p) .or. isMultiwire(cables(i)%p)) then + is_read = .true. + read_cable = readMTLNCable(cables(i)%p, is_read) + if (.not. isCableNameUnique(read_cable, mtln_res%cables, ncc)) then + error stop 'Cable name "'//read_cable%name//'" has already been used' + end if + ncc = ncc + 1 + mtln_res%cables(ncc) = read_cable + call addElemIdToCableMap(elemIdToCable, getCableElemIds(cables(i)%p), ncc) + call addElemIdToPositionMap(elemIdToPosition, cables(i)%p) + end if + end do + end if end block block integer :: i, j, parentId, index - type(json_value_ptr) :: mat j = 1 - do i = 1, size(cables) - mat = this%matTable%getId(cables(i)%materialId) - if (this%getStrAt(mat%p, J_TYPE) == J_MAT_TYPE_MULTIWIRE) then - parentId = cables(i)%containedWithinElementId - if (parentId == -1) then + if (size(cables) /= 0) then + do i = 1, size(cables) + if (isMultiwire(cables(i)%p)) then + parentId = this%getIntAt(cables(i)%p, J_MAT_ASS_CAB_CONTAINED_WITHIN_ID, default=0) + if (parentId == 0) then + mtln_res%cables(j)%parent_cable => null() + mtln_res%cables(j)%conductor_in_parent = 0 + else + call elemIdToCable%get(key(parentId), value=index) + mtln_res%cables(j)%parent_cable => mtln_res%cables(index) + mtln_res%cables(j)%conductor_in_parent = getParentPositionInMultiwire(parentId) + end if + else if (isWire(cables(i)%p)) then mtln_res%cables(j)%parent_cable => null() mtln_res%cables(j)%conductor_in_parent = 0 - else - call elemIdToCable%get(key(parentId), value=index) - mtln_res%cables(j)%parent_cable => mtln_res%cables(index) - mtln_res%cables(j)%conductor_in_parent = getParentPositionInMultiwire(parentId) end if - else if (this%getStrAt(mat%p, J_TYPE) == J_MAT_TYPE_WIRE) then - mtln_res%cables(j)%parent_cable => null() - mtln_res%cables(j)%conductor_in_parent = 0 - else - write(error_unit, *) 'ERROR: Material type not recognized' - end if - j = j + 1 - end do + j = j + 1 + end do + end if end block + mtln_res%probes = readWireProbes() mtln_res%networks = buildNetworks() @@ -2170,6 +2140,37 @@ function readConnectors() result(res) end function + function countNumberOfMultiwires(cables) result (res) + type(json_value_ptr), dimension(:), intent(in) :: cables + type(json_value_ptr) :: material + integer :: i + integer :: res + res = 0 + if (size(cables) /= 0) then + do i = 1, size(cables) + if (isMultiwire(cables(i)%p)) then + res = res + 1 + end if + end do + end if + end function + + function countNumberOfWires(cables) result (res) + type(json_value_ptr), dimension(:), intent(in) :: cables + type(json_value_ptr) :: material + integer :: i + integer :: res + res = 0 + if (size(cables) /= 0) then + do i = 1, size(cables) + if (isWire(cables(i)%p)) then + material = this%matTable%getId(this%getIntAt(cables(i)%p, J_MATERIAL_ID)) + res = res + 1 + end if + end do + end if + end function + function findMaxElemId(cables) result(res) type(json_value_ptr), dimension(:), intent(in) :: cables integer :: i, m @@ -2190,25 +2191,37 @@ function findMaxElemId(cables) result(res) end function + function readCables() result(res) + type(json_value), pointer :: matAss + type(json_value_ptr), dimension(:), allocatable :: res + if (this%existsAt(this%root, J_MATERIAL_ASSOCIATIONS)) then + call this%core%get(this%root, J_MATERIAL_ASSOCIATIONS, matAss) + res = this%jsonValueFilterByKeyValue(matAss, J_TYPE, J_MAT_ASS_TYPE_CABLE) + else + allocate(res(0)) + end if + end function + + function buildNetworks() result(res) type(terminal_network_t), dimension(:), allocatable :: res type(aux_node_t), dimension(:), allocatable :: aux_nodes + type(json_value_ptr), dimension(:), allocatable :: cables integer :: i,j integer, dimension(:), allocatable :: elemIds type(json_value), pointer :: terminations_ini, terminations_end type(coordinate_t), dimension(:), allocatable :: networks_coordinates type(subcircuit_t), dimension(:), allocatable :: subcircuits - type(materialAssociation_t), dimension(:), allocatable :: cables + subcircuits = readSubcircuits() allocate(aux_nodes(0)) allocate(networks_coordinates(0)) - cables = [ this%getMaterialAssociations([J_MAT_TYPE_WIRE]), & - this%getMaterialAssociations([J_MAT_TYPE_MULTIWIRE]) ] + cables = readCables() do i = 1, size(cables) - elemIds = cables(i)%elementIds - terminations_ini => getTerminationsOnSide(cables(i)%initialTerminalId) - terminations_end => getTerminationsOnSide(cables(i)%endTerminalId) + elemIds = getCableElemIds(cables(i)%p) + terminations_ini => getTerminationsOnSide(cables(i)%p, J_MAT_ASS_CAB_INI_TERM_ID) + terminations_end => getTerminationsOnSide(cables(i)%p, J_MAT_ASS_CAB_END_TERM_ID) do j = 1, size(elemIds) aux_nodes = [aux_nodes, buildNode(terminations_ini, TERMINAL_NODE_SIDE_INI, j, elemIds(j))] aux_nodes = [aux_nodes, buildNode(terminations_end, TERMINAL_NODE_SIDE_END, j, elemIds(j))] @@ -2394,17 +2407,18 @@ subroutine updateListOfNetworksCoordinates(coordinates, conductor_index) end subroutine - function getTerminationsOnSide(terminationId) result(res) - integer, intent(in) :: terminationId + function getTerminationsOnSide(cable, label) result(res) + type(json_value), pointer :: cable + character(*), intent(in) :: label type(json_value_ptr) :: terminal type(json_value), pointer :: res - if (terminationId == -1) then + if (.not. this%existsAt(cable, label)) then write(error_unit, *) 'Error: missing terminal on cable side' res => null() return end if - terminal = this%matTable%getId(terminationId) + terminal = this%matTable%getId(this%getIntAt(cable, label)) if (.not. this%existsAt(terminal%p, J_MAT_TERM_TERMINATIONS)) then write(error_unit, *) 'Error: missing terminations on terminal' res => null() @@ -2748,11 +2762,13 @@ function getCableContainingElemId(id) result(res) end select end function - function findConnectorWithId(conn_Id) result(res) - integer, intent(in) :: conn_id - integer :: conn_index + function findConnectorWithId(j_cable, side) result(res) + type(json_value), pointer :: j_cable + character(*), intent(in) :: side + integer :: conn_id, conn_index type(connector_t), pointer :: res - if (conn_id /= -1) then + if (this%existsAt(j_cable, side)) then + conn_id = this%getIntAt(j_cable, side) call connIdToConnector%get(key(conn_id), conn_index) res => mtln_res%connectors(conn_index) else @@ -2817,10 +2833,12 @@ subroutine addElemIdToCableMap(map, elemIds, index) end do end subroutine - subroutine addElemIdToPositionMap(map, elemIds) + subroutine addElemIdToPositionMap(map, j_cable) type(fhash_tbl_t), intent(inout) :: map - integer, dimension(:), allocatable, intent(in) :: elemIds + type(json_value), pointer :: j_cable + integer, dimension(:), allocatable :: elemIds integer :: i + elemIds = getCableElemIds(j_cable) do i = 1, size(elemIds) call map%set(key(elemIds(i)), i) end do @@ -2839,22 +2857,27 @@ function getCableElemIds(cable) result(res) function readMTLNCable(j_cable, is_read) result(res) - type(materialAssociation_t), intent(in) :: j_cable + type(json_value), pointer :: j_cable type(cable_t) :: res type(json_value_ptr) :: material logical, intent(inout) :: is_read integer :: nConductors logical :: found - character(:), allocatable :: materialType - res%name = j_cable%name + if (this%existsAt(j_cable,J_NAME)) then + res%name = trim(adjustl(this%getStrAt(j_cable,J_NAME))) + else + res%name = "" + end if res%step_size = buildStepSize(j_cable) res%external_field_segments = mapSegmentsToGridCoordinates(j_cable) - material = this%matTable%getId(j_cable%materialId) - materialType = this%getStrAt(material%p, J_TYPE) - if (materialType == J_MAT_TYPE_WIRE) then + material = this%matTable%getId(this%getIntAt(j_cable, J_MATERIAL_ID, found)) + if (.not. found) & + write(error_unit, *) "Error reading material region: materialId label not found." + + if (isWire(j_cable)) then call assignReferenceProperties(res, material) call assignExternalRadius(res, material) if (this%existsAt(material%p, J_MAT_WIRE_DIELECTRIC)) then @@ -2865,14 +2888,16 @@ function readMTLNCable(j_cable, is_read) result(res) res%isPassthrough = this%getLogicalAt(material%p, J_MAT_WIRE_PASS) end if - else if (materialType == J_MAT_TYPE_MULTIWIRE) then - call assignPULProperties(res, material, size(j_cable%elementIds)) + else if (isMultiwire(j_cable)) then + call assignPULProperties(res, material, size(getCableElemIds(j_cable))) else write(error_unit, *) "Error reading cable: is neither wire nor multiwire" end if - res%initial_connector => findConnectorWithId(j_cable%initialConnectorId) - res%end_connector => findConnectorWithId(j_cable%endConnectorId) + + + res%initial_connector => findConnectorWithId(j_cable, J_MAT_ASS_CAB_INI_CONN_ID) + res%end_connector => findConnectorWithId(j_cable, J_MAT_ASS_CAB_END_CONN_ID) res%transfer_impedance = buildTransferImpedance(material) @@ -3031,12 +3056,12 @@ subroutine assignPULProperties(res, mat, n) end subroutine function mapSegmentsToGridCoordinates(j_cable) result(res) - type(materialAssociation_t), intent(in) :: j_cable + type(json_value), pointer :: j_cable type(external_field_segment_t), dimension(:), allocatable :: res integer, dimension(:), allocatable :: elemIds type(polyline_t) :: p_line - elemIds = j_cable%elementIds + elemIds = getCableElemIds(j_cable) if (size(elemIds) == 0) return p_line = this%mesh%getPolyline(elemIds(1)) @@ -3096,7 +3121,7 @@ function mapPositiveSegment(c1, c2) result(res) end function function buildStepSize(j_cable) result(res) - type(materialAssociation_t), intent(in) :: j_cable + type(json_value), pointer :: j_cable real, dimension(:), allocatable :: res integer, dimension(:), allocatable :: elemIds type(polyline_t) :: p_line @@ -3104,7 +3129,7 @@ function buildStepSize(j_cable) result(res) desp = this%readGrid() - elemIds = j_cable%elementIds + elemIds = getCableElemIds(j_cable) if (size(elemIds) == 0) return p_line = this%mesh%getPolyline(elemIds(1)) @@ -3240,6 +3265,66 @@ function findDirection(coordDiference) result(res) end do end function + logical function isMultiwire(cable) + type(json_value), pointer :: cable + type(json_value_ptr) :: mat + integer, dimension(:), allocatable :: eIds + logical :: found + + isMultiwire = .false. + + ! materialId is multiwire + mat = this%matTable%getId(this%getIntAt(cable, J_MATERIAL_ID, found=found)) + if (.not. found) return + if (this%getStrAt(mat%p, J_TYPE) /= J_MAT_TYPE_MULTIWIRE) return + + ! has terminal on initial side + mat = this%matTable%getId(this%getIntAt(cable, J_MAT_ASS_CAB_INI_TERM_ID, found=found)) + if (.not. found) return + if (this%getStrAt(mat%p, J_TYPE) /= J_MAT_TYPE_TERMINAL) return + + ! has terminal on end side + mat = this%matTable%getId(this%getIntAt(cable, J_MAT_ASS_CAB_END_TERM_ID, found=found)) + if (.not. found) return + if (this%getStrAt(mat%p, J_TYPE) /= J_MAT_TYPE_TERMINAL) return + + ! has elementIds + eIds = this%getIntsAt(cable, J_ELEMENTIDS, found=found) + if (.not. found) return + + isMultiwire = .true. + + end function + + logical function isWire(cable) + type(json_value), pointer :: cable + type(json_value_ptr) :: mat + integer, dimension(:), allocatable :: eIds + logical :: found + isWire = .false. + + ! materialId is wire + mat = this%matTable%getId(this%getIntAt(cable, J_MATERIAL_ID, found=found)) + if (.not. found) return + if (this%getStrAt(mat%p, J_TYPE) /= J_MAT_TYPE_WIRE) return + + ! has terminal on initial side + mat = this%matTable%getId(this%getIntAt(cable, J_MAT_ASS_CAB_INI_TERM_ID, found=found)) + if (.not. found) return + if (this%getStrAt(mat%p, J_TYPE) /= J_MAT_TYPE_TERMINAL) return + + ! has terminal on end side + mat = this%matTable%getId(this%getIntAt(cable, J_MAT_ASS_CAB_END_TERM_ID, found=found)) + if (.not. found) return + if (this%getStrAt(mat%p, J_TYPE) /= J_MAT_TYPE_TERMINAL) return + + ! has elementIds + eIds = this%getIntsAt(cable, J_ELEMENTIDS, found=found) + if (.not. found) return + + isWire = .true. + + end function end function #endif diff --git a/src_json_parser/smbjson_labels.F90 b/src_json_parser/smbjson_labels.F90 index dc9d550b..d04a306f 100644 --- a/src_json_parser/smbjson_labels.F90 +++ b/src_json_parser/smbjson_labels.F90 @@ -79,6 +79,11 @@ module smbjson_labels_mod character (len=*), parameter :: J_MATERIAL_ID = "materialId" character (len=*), parameter :: J_MATERIAL_PASS = "materialId" + character (len=*), parameter :: J_MAT_ASS_TYPE_BULK = "bulk" + character (len=*), parameter :: J_MAT_ASS_TYPE_SURFACE = "surface" + character (len=*), parameter :: J_MAT_ASS_TYPE_LINE = "line" + character (len=*), parameter :: J_MAT_ASS_TYPE_CABLE = "cable" + character (len=*), parameter :: J_MAT_ASS_CAB_INI_TERM_ID = "initialTerminalId" character (len=*), parameter :: J_MAT_ASS_CAB_END_TERM_ID = "endTerminalId" character (len=*), parameter :: J_MAT_ASS_CAB_INI_CONN_ID = "initialConnectorId" diff --git a/test/pyWrapper/test_full_system.py b/test/pyWrapper/test_full_system.py index 2553d0d7..08730c2b 100644 --- a/test/pyWrapper/test_full_system.py +++ b/test/pyWrapper/test_full_system.py @@ -1,7 +1,6 @@ from utils import * import pytest -@no_mtln_skip @pytest.mark.mtln def test_shieldedPair(tmp_path): fn = CASE_FOLDER + 'shieldedPair/shieldedPair.fdtd.json' @@ -32,7 +31,6 @@ def test_shieldedPair(tmp_path): p_solved = Probe(probe_files[i]) assert np.allclose(p_expected[i].df.to_numpy()[:,0:4], p_solved.df.to_numpy()[:,0:4], rtol = 5e-2, atol=0.2) -@no_mtln_skip @pytest.mark.mtln def test_coated_antenna(tmp_path): fn = CASE_FOLDER + 'coated_antenna/coated_antenna.fdtd.json' @@ -69,7 +67,6 @@ def test_holland(tmp_path): p_solved = Probe(probe_files[0]) assert np.allclose(p_expected.df.to_numpy()[:,0:3], p_solved.df.to_numpy()[:,0:3], rtol = 1e-5, atol=1e-6) -@no_mtln_skip @pytest.mark.mtln def test_holland_mtln(tmp_path): fn = CASE_FOLDER + 'holland/holland1981.fdtd.json' @@ -106,8 +103,8 @@ def test_towelHanger(tmp_path): p_solved = Probe(probe_files[i]) assert np.allclose(p_expected[i].df.to_numpy()[:,0:3], p_solved.df.to_numpy()[:,0:3], rtol = 5e-2, atol=5e-2) -@no_hdf_skip -@pytest.mark.hdf + +@pytest.mark.hdf5 def test_sphere(tmp_path): fn = CASE_FOLDER + 'sphere/sphere.fdtd.json' solver = FDTD(input_filename = fn, path_to_exe=SEMBA_EXE, run_in_folder=tmp_path) diff --git a/test/pyWrapper/test_mtln_standalone.py b/test/pyWrapper/test_mtln_standalone.py index 963c5b1d..b80ac0bb 100644 --- a/test/pyWrapper/test_mtln_standalone.py +++ b/test/pyWrapper/test_mtln_standalone.py @@ -1,7 +1,6 @@ from utils import * import pytest -@no_mtln_skip @pytest.mark.mtln def test_paul_8_6_square(tmp_path): case = 'paul_8_6_square' @@ -22,7 +21,6 @@ def test_paul_8_6_square(tmp_path): assert np.allclose(p_expected.df.to_numpy()[:,0:2], p_solved.df.to_numpy()[:,0:2], rtol = 0.01, atol=0.2) -@no_mtln_skip @pytest.mark.mtln def test_paul_8_6_triangle(tmp_path): case = 'paul_8_6_triangle' @@ -43,7 +41,6 @@ def test_paul_8_6_triangle(tmp_path): assert np.allclose(p_expected.df.to_numpy()[:,0:2], p_solved.df.to_numpy()[:,0:2], rtol = 0.01, atol=0.5) -@no_mtln_skip @pytest.mark.mtln def test_paul_9_6(tmp_path): case = 'paul_9_6' @@ -67,7 +64,6 @@ def test_paul_9_6(tmp_path): for i in range(2): assert np.allclose(p_expected[i].df.to_numpy()[:,:], p_solved[i].df.to_numpy()[:,:], rtol = 0.01, atol=0.5) -@no_mtln_skip @pytest.mark.mtln def test_spice_multilines_opamp(tmp_path): case = 'multilines_opamp' @@ -88,7 +84,6 @@ def test_spice_multilines_opamp(tmp_path): assert np.allclose(p_expected[0].df.to_numpy()[:-1,:], p_solved[0].df.to_numpy()[:-1,:], rtol = 0.01, atol=0.05e-3) -@no_mtln_skip @pytest.mark.mtln def test_spice_connector_diode(tmp_path): case = 'spice_connectors' @@ -113,7 +108,6 @@ def test_spice_connector_diode(tmp_path): for i in range(2): assert np.allclose(p_expected[i].df.to_numpy()[:-20,:], p_solved[i].df.to_numpy()[:-20,:], rtol = 0.01, atol=0.05e-3) -@no_mtln_skip @pytest.mark.mtln def test_line_multiline_junction(tmp_path): case = 'line_multiline_junction' @@ -137,7 +131,6 @@ def test_line_multiline_junction(tmp_path): for i in range(3): assert np.allclose(p_expected[i].df.to_numpy()[:-20,:], Probe(probe_files[i]).df.to_numpy()[:-20,:], rtol = 0.01, atol=5e-3) -@no_mtln_skip @pytest.mark.mtln @pytest.mark.codemodel def test_spice_opamp_saturation(tmp_path): diff --git a/test/pyWrapper/utils.py b/test/pyWrapper/utils.py index f744b76c..441c1eb3 100644 --- a/test/pyWrapper/utils.py +++ b/test/pyWrapper/utils.py @@ -4,20 +4,9 @@ import numpy as np import matplotlib.pyplot as plt import pyvista as pv -import pytest from os import environ as env from sys import platform -no_mtln_skip = pytest.mark.skipif( - os.getenv("SEMBA_FDTD_ENABLE_MTLN") == "No", - reason="MTLN is not available", -) - -no_hdf_skip = pytest.mark.skipif( - os.getenv("SEMBA_FDTD_ENABLE_HDF") == "No", - reason="HDF5 is not available", -) - # Use of absolute path to avoid conflicts when changing directory. if platform == "linux": SEMBA_EXE = os.path.join(os.getcwd(), 'build', 'bin', 'semba-fdtd') diff --git a/test/smbjson/test_parser.F90 b/test/smbjson/test_parser.F90 index a2d07bf7..4d6e9773 100644 --- a/test/smbjson/test_parser.F90 +++ b/test/smbjson/test_parser.F90 @@ -4,15 +4,12 @@ integer function test_parser_ctor() bind(C) result(err) implicit none - character(len=*),parameter :: filename = PATH_TO_TEST_DATA//INPUT_EXAMPLES//'planewave.fdtd.json' + character(len=*),parameter :: filename = PATH_TO_TEST_DATA//'cases/planewave.fdtd.json' type(parser_t) :: parser - + err = 0 + parser = parser_t(filename) - if (parser%isInitialized) then - err = 0 - else - err = 1 - end if + end function integer function test_parser_tools_interval_to_coords() result(err) diff --git a/testData/cases/coated_antenna/coated_antenna.fdtd.json b/testData/cases/coated_antenna/coated_antenna.fdtd.json index f5b497d9..1c09ddc8 100644 --- a/testData/cases/coated_antenna/coated_antenna.fdtd.json +++ b/testData/cases/coated_antenna/coated_antenna.fdtd.json @@ -64,14 +64,16 @@ "materialAssociations": [ { - "name" : "half_1", + "type": "cable", + "name" : "half_1", "materialId": 1, "initialTerminalId": 2, "endTerminalId": 3, "elementIds": [2] }, { - "name" : "half_2", + "type": "cable", + "name" : "half_2", "materialId": 1, "initialTerminalId": 3, "endTerminalId": 2, diff --git a/testData/cases/holland/holland1981.fdtd.json b/testData/cases/holland/holland1981.fdtd.json index 51261c4b..3528a06d 100644 --- a/testData/cases/holland/holland1981.fdtd.json +++ b/testData/cases/holland/holland1981.fdtd.json @@ -52,7 +52,8 @@ "materialAssociations": [ { - "name" : "single_wire", + "type": "cable", + "name" : "single_wire", "materialId": 1, "initialTerminalId": 2, "endTerminalId": 2, diff --git a/testData/cases/holland_with_dielectric.fdtd.json b/testData/cases/holland_with_dielectric.fdtd.json index a5f848f2..8e516af8 100644 --- a/testData/cases/holland_with_dielectric.fdtd.json +++ b/testData/cases/holland_with_dielectric.fdtd.json @@ -53,6 +53,7 @@ "materialAssociations": [ { + "type": "cable", "name" : "single_wire", "materialId": 1, "initialTerminalId": 2, diff --git a/testData/cases/line_multiline_junction.fdtd.json b/testData/cases/line_multiline_junction.fdtd.json index 4508759a..169d9800 100644 --- a/testData/cases/line_multiline_junction.fdtd.json +++ b/testData/cases/line_multiline_junction.fdtd.json @@ -133,6 +133,7 @@ "materialAssociations": [ { "name": "s1", + "type": "cable", "elementIds": [ 1 ], "materialId": 1, "initialTerminalId": 4, @@ -140,6 +141,7 @@ }, { "name": "s2", + "type": "cable", "elementIds": [ 2 ], "materialId": 1, "initialTerminalId": 3, @@ -147,6 +149,7 @@ }, { "name": "s3", + "type": "cable", "elementIds": [ 3,4 ], "materialId": 2, "initialTerminalId": 5, @@ -154,6 +157,7 @@ }, { "name": "s4", + "type": "cable", "elementIds": [ 5 ], "materialId": 1, "initialTerminalId": 6, @@ -161,6 +165,7 @@ }, { "name": "s5", + "type": "cable", "elementIds": [ 6 ], "materialId": 1, "initialTerminalId": 6, diff --git a/testData/cases/line_multiline_junction_with_wires.fdtd.json b/testData/cases/line_multiline_junction_with_wires.fdtd.json index c1dc4c9c..ad95521e 100644 --- a/testData/cases/line_multiline_junction_with_wires.fdtd.json +++ b/testData/cases/line_multiline_junction_with_wires.fdtd.json @@ -133,6 +133,7 @@ "materialAssociations": [ { "name": "s1", + "type": "cable", "elementIds": [ 1 ], "materialId": 1, "initialTerminalId": 4, @@ -140,6 +141,7 @@ }, { "name": "s2", + "type": "cable", "elementIds": [ 2 ], "materialId": 1, "initialTerminalId": 3, @@ -147,6 +149,7 @@ }, { "name": "s3", + "type": "cable", "elementIds": [ 3,4 ], "materialId": 2, "initialTerminalId": 5, @@ -154,6 +157,7 @@ }, { "name": "s4", + "type": "cable", "elementIds": [ 5 ], "materialId": 1, "initialTerminalId": 6, @@ -161,6 +165,7 @@ }, { "name": "s5", + "type": "cable", "elementIds": [ 6 ], "materialId": 1, "initialTerminalId": 6, diff --git a/testData/cases/multilines_4port_box.fdtd.json b/testData/cases/multilines_4port_box.fdtd.json index c1492ac2..22233892 100644 --- a/testData/cases/multilines_4port_box.fdtd.json +++ b/testData/cases/multilines_4port_box.fdtd.json @@ -137,14 +137,16 @@ "materialAssociations": [ { "name": "s1", - "elementIds": [ 1,2 ], + "type": "cable", + "elementIds": [ 1,2 ], "materialId": 1, "initialTerminalId": 2, "endTerminalId": 3 }, { "name": "s2", - "elementIds": [ 3,4 ], + "type": "cable", + "elementIds": [ 3,4 ], "materialId": 1, "initialTerminalId": 4, "endTerminalId": 2 diff --git a/testData/cases/multilines_4port_box_nobox.fdtd.json b/testData/cases/multilines_4port_box_nobox.fdtd.json index 7cd42a1d..24027ad6 100644 --- a/testData/cases/multilines_4port_box_nobox.fdtd.json +++ b/testData/cases/multilines_4port_box_nobox.fdtd.json @@ -130,14 +130,16 @@ "materialAssociations": [ { "name": "s1", - "elementIds": [ 1,2 ], + "type": "cable", + "elementIds": [ 1,2 ], "materialId": 1, "initialTerminalId": 2, "endTerminalId": 3 }, { "name": "s2", - "elementIds": [ 3,4 ], + "type": "cable", + "elementIds": [ 3,4 ], "materialId": 1, "initialTerminalId": 4, "endTerminalId": 2 diff --git a/testData/cases/multilines_balun.fdtd.json b/testData/cases/multilines_balun.fdtd.json index 82f23a64..99e1caf4 100644 --- a/testData/cases/multilines_balun.fdtd.json +++ b/testData/cases/multilines_balun.fdtd.json @@ -137,14 +137,16 @@ "materialAssociations": [ { "name": "s1", - "elementIds": [ 1,2 ], + "type": "cable", + "elementIds": [ 1,2 ], "materialId": 1, "initialTerminalId": 2, "endTerminalId": 3 }, { "name": "s2", - "elementIds": [ 3,4 ], + "type": "cable", + "elementIds": [ 3,4 ], "materialId": 1, "initialTerminalId": 4, "endTerminalId": 2 diff --git a/testData/cases/multilines_opamp.fdtd.json b/testData/cases/multilines_opamp.fdtd.json index 8508b128..5bdb30e8 100644 --- a/testData/cases/multilines_opamp.fdtd.json +++ b/testData/cases/multilines_opamp.fdtd.json @@ -137,14 +137,16 @@ "materialAssociations": [ { "name": "s1", - "elementIds": [ 1,2 ], + "type": "cable", + "elementIds": [ 1,2 ], "materialId": 1, "initialTerminalId": 2, "endTerminalId": 3 }, { "name": "s2", - "elementIds": [ 3,4 ], + "type": "cable", + "elementIds": [ 3,4 ], "materialId": 1, "initialTerminalId": 4, "endTerminalId": 2 diff --git a/testData/cases/opamp_saturation.fdtd.json b/testData/cases/opamp_saturation.fdtd.json index b6808b4c..a5259da1 100644 --- a/testData/cases/opamp_saturation.fdtd.json +++ b/testData/cases/opamp_saturation.fdtd.json @@ -95,7 +95,8 @@ "materialAssociations": [ { "name": "wire1", - "elementIds": [ 1, 2 ], + "type": "cable", + "elementIds": [ 1, 2 ], "materialId": 1, "initialTerminalId": 2, "endTerminalId": 3 diff --git a/testData/cases/paul_8_6_square.fdtd.json b/testData/cases/paul_8_6_square.fdtd.json index de56e663..00a8f83f 100644 --- a/testData/cases/paul_8_6_square.fdtd.json +++ b/testData/cases/paul_8_6_square.fdtd.json @@ -92,7 +92,8 @@ "materialAssociations": [ { "name": "wire", - "elementIds": [ 1 ], + "type": "cable", + "elementIds": [ 1 ], "materialId": 1, "initialTerminalId": 2, "endTerminalId": 3 diff --git a/testData/cases/paul_8_6_triangle.fdtd.json b/testData/cases/paul_8_6_triangle.fdtd.json index 393ab799..6c4000c7 100644 --- a/testData/cases/paul_8_6_triangle.fdtd.json +++ b/testData/cases/paul_8_6_triangle.fdtd.json @@ -92,7 +92,8 @@ "materialAssociations": [ { "name": "wire", - "elementIds": [ 1 ], + "type": "cable", + "elementIds": [ 1 ], "materialId": 1, "initialTerminalId": 2, "endTerminalId": 3 diff --git a/testData/cases/paul_9_6.fdtd.json b/testData/cases/paul_9_6.fdtd.json index 70e055b5..a20f14e1 100644 --- a/testData/cases/paul_9_6.fdtd.json +++ b/testData/cases/paul_9_6.fdtd.json @@ -104,7 +104,8 @@ "materialAssociations": [ { "name": "two_wires", - "elementIds": [ 1,2 ], + "type": "cable", + "elementIds": [ 1,2 ], "materialId": 1, "initialTerminalId": 2, "endTerminalId": 3 diff --git a/testData/cases/sgbc/sgbc.fdtd.json b/testData/cases/sgbc/sgbc.fdtd.json index 2ffb5130..63c0cf48 100644 --- a/testData/cases/sgbc/sgbc.fdtd.json +++ b/testData/cases/sgbc/sgbc.fdtd.json @@ -51,7 +51,8 @@ "materialAssociations": [ { - "materialId": 1, + "type": "bulk", + "materialId": 1, "elementIds": [ 1 ] }, { diff --git a/testData/cases/shieldedPair/shieldedPair.fdtd.json b/testData/cases/shieldedPair/shieldedPair.fdtd.json index fa9e584c..6459d1fd 100644 --- a/testData/cases/shieldedPair/shieldedPair.fdtd.json +++ b/testData/cases/shieldedPair/shieldedPair.fdtd.json @@ -167,21 +167,24 @@ "materialAssociations": [ { "name": "line_0", - "elementIds": [ 1 ], + "type": "cable", + "elementIds": [ 1 ], "materialId": 2, "initialTerminalId": 6, "endTerminalId": 6 }, { "name": "line_1", - "elementIds": [ 6,7 ], + "type": "cable", + "elementIds": [ 6,7 ], "materialId": 1, "initialTerminalId": 3, "endTerminalId": 3, "containedWithinElementId": 1 }, { - "materialId" : 5, + "type": "bulk", + "materialId" : 5, "elementIds": [5] } diff --git a/testData/cases/sphere/sphere.fdtd.json b/testData/cases/sphere/sphere.fdtd.json index 2690a2b2..3f306146 100644 --- a/testData/cases/sphere/sphere.fdtd.json +++ b/testData/cases/sphere/sphere.fdtd.json @@ -40903,7 +40903,8 @@ ], "materialAssociations": [ { - "materialId": 1, + "type": "surface", + "materialId": 1, "elementIds": [ 3 ] diff --git a/testData/cases/spice_connectors.fdtd.json b/testData/cases/spice_connectors.fdtd.json index 4c56594d..d1eacbe2 100644 --- a/testData/cases/spice_connectors.fdtd.json +++ b/testData/cases/spice_connectors.fdtd.json @@ -92,7 +92,8 @@ "materialAssociations": [ { "name": "wire", - "elementIds": [ 1 ], + "type": "cable", + "elementIds": [ 1 ], "materialId": 1, "initialTerminalId": 2, "endTerminalId": 3 diff --git a/testData/cases/towelHanger/towelHanger.fdtd.json b/testData/cases/towelHanger/towelHanger.fdtd.json index cf52f6fa..108676f7 100644 --- a/testData/cases/towelHanger/towelHanger.fdtd.json +++ b/testData/cases/towelHanger/towelHanger.fdtd.json @@ -69,14 +69,16 @@ "materialAssociations": [ { - "name": "wire", + "type": "cable", + "name": "wire", "materialId": 1, "initialTerminalId": 2, "endTerminalId": 3, "elementIds": [2] }, { - "materialId" : 4, + "type": "bulk", + "materialId" : 4, "elementIds": [3] } ], diff --git a/testData/cases/wire_panel.fdtd.json b/testData/cases/wire_panel.fdtd.json index 43c980dc..c0a671b3 100644 --- a/testData/cases/wire_panel.fdtd.json +++ b/testData/cases/wire_panel.fdtd.json @@ -115,7 +115,8 @@ "materialAssociations": [ { "name": "panel", - "elementIds": [ 1,2,3,4 ], + "type": "cable", + "elementIds": [ 1,2,3,4 ], "materialId": 1, "initialTerminalId": 2, "endTerminalId": 2 diff --git a/testData/input_examples/connectedWires.fdtd.json b/testData/input_examples/connectedWires.fdtd.json index a2785d4d..094cf8b1 100644 --- a/testData/input_examples/connectedWires.fdtd.json +++ b/testData/input_examples/connectedWires.fdtd.json @@ -65,14 +65,16 @@ "materialAssociations": [ { - "name": "cable1", + "type": "cable", + "name": "cable1", "materialId": 1, "initialTerminalId": 3, "endTerminalId": 2, "elementIds": [2] }, { - "name": "cable2", + "type": "cable", + "name": "cable2", "materialId": 1, "initialTerminalId": 3, "endTerminalId": 3, diff --git a/testData/input_examples/holland1981.fdtd.json b/testData/input_examples/holland1981.fdtd.json index 51261c4b..3528a06d 100644 --- a/testData/input_examples/holland1981.fdtd.json +++ b/testData/input_examples/holland1981.fdtd.json @@ -52,7 +52,8 @@ "materialAssociations": [ { - "name" : "single_wire", + "type": "cable", + "name" : "single_wire", "materialId": 1, "initialTerminalId": 2, "endTerminalId": 2, diff --git a/testData/input_examples/large_airplane_mtln.fdtd.json b/testData/input_examples/large_airplane_mtln.fdtd.json index 13e1fee2..976f841d 100644 --- a/testData/input_examples/large_airplane_mtln.fdtd.json +++ b/testData/input_examples/large_airplane_mtln.fdtd.json @@ -46867,7 +46867,8 @@ }, { "name": "Cable000", - "elementIds": [ + "type": "cable", + "elementIds": [ 36 ], "materialId": 2, @@ -46876,7 +46877,8 @@ }, { "name": "Cable001", - "elementIds": [ + "type": "cable", + "elementIds": [ 37 ], "materialId": 2, @@ -46885,7 +46887,8 @@ }, { "name": "Cable002", - "elementIds": [ + "type": "cable", + "elementIds": [ 38 ], "materialId": 2, @@ -46894,7 +46897,8 @@ }, { "name": "Cable003", - "elementIds": [ + "type": "cable", + "elementIds": [ 39 ], "materialId": 2, @@ -46903,7 +46907,8 @@ }, { "name": "Cable004", - "elementIds": [ + "type": "cable", + "elementIds": [ 40 ], "materialId": 2, @@ -46912,7 +46917,8 @@ }, { "name": "Cable005", - "elementIds": [ + "type": "cable", + "elementIds": [ 41 ], "materialId": 2, @@ -46921,7 +46927,8 @@ }, { "name": "Cable006", - "elementIds": [ + "type": "cable", + "elementIds": [ 42 ], "materialId": 2, @@ -46930,7 +46937,8 @@ }, { "name": "Cable007", - "elementIds": [ + "type": "cable", + "elementIds": [ 43 ], "materialId": 2, @@ -46939,7 +46947,8 @@ }, { "name": "Cable008", - "elementIds": [ + "type": "cable", + "elementIds": [ 44 ], "materialId": 2, @@ -46948,7 +46957,8 @@ }, { "name": "Cable009", - "elementIds": [ + "type": "cable", + "elementIds": [ 45 ], "materialId": 2, @@ -46957,7 +46967,8 @@ }, { "name": "Cable010", - "elementIds": [ + "type": "cable", + "elementIds": [ 46 ], "materialId": 2, @@ -46966,7 +46977,8 @@ }, { "name": "InnerBundle_Cable010", - "elementIds": [ + "type": "cable", + "elementIds": [ 47, 48 ], @@ -46977,7 +46989,8 @@ }, { "name": "InnerBundle_Cable009", - "elementIds": [ + "type": "cable", + "elementIds": [ 49, 50 ], @@ -46988,7 +47001,8 @@ }, { "name": "InnerBundle_Cable008", - "elementIds": [ + "type": "cable", + "elementIds": [ 51, 52 ], @@ -46999,7 +47013,8 @@ }, { "name": "InnerBundle_Cable007", - "elementIds": [ + "type": "cable", + "elementIds": [ 53, 54 ], @@ -47010,7 +47025,8 @@ }, { "name": "InnerBundle_Cable006", - "elementIds": [ + "type": "cable", + "elementIds": [ 55, 56 ], @@ -47021,7 +47037,8 @@ }, { "name": "InnerBundle_Cable005", - "elementIds": [ + "type": "cable", + "elementIds": [ 57, 58 ], @@ -47032,7 +47049,8 @@ }, { "name": "InnerBundle_Cable004", - "elementIds": [ + "type": "cable", + "elementIds": [ 59, 60 ], @@ -47043,7 +47061,8 @@ }, { "name": "InnerBundle_Cable003", - "elementIds": [ + "type": "cable", + "elementIds": [ 61, 62 ], @@ -47054,7 +47073,8 @@ }, { "name": "InnerBundle_Cable002", - "elementIds": [ + "type": "cable", + "elementIds": [ 63, 64 ], @@ -47065,7 +47085,8 @@ }, { "name": "InnerBundle_Cable001", - "elementIds": [ + "type": "cable", + "elementIds": [ 65, 66 ], @@ -47076,7 +47097,8 @@ }, { "name": "InnerBundle_Cable000", - "elementIds": [ + "type": "cable", + "elementIds": [ 67, 68 ], diff --git a/testData/input_examples/mtln.fdtd.json b/testData/input_examples/mtln.fdtd.json index afe5698e..3b3c6505 100644 --- a/testData/input_examples/mtln.fdtd.json +++ b/testData/input_examples/mtln.fdtd.json @@ -404,7 +404,8 @@ "materialAssociations": [ { "name": "line_0_0", - "elementIds": [ 1 ], + "type": "cable", + "elementIds": [ 1 ], "materialId": 10, "initialTerminalId": 20, "endTerminalId": 7, @@ -412,7 +413,8 @@ }, { "name": "line_1_0", - "elementIds": [ 6 ], + "type": "cable", + "elementIds": [ 6 ], "materialId": 2, "initialTerminalId": 7, "endTerminalId": 7, @@ -421,7 +423,8 @@ }, { "name": "line_2_0", - "elementIds": [ 17, 18, 19, 20, 21, 22, 23, 24 ], + "type": "cable", + "elementIds": [ 17, 18, 19, 20, 21, 22, 23, 24 ], "materialId": 61, "initialTerminalId": 100, "endTerminalId": 78, @@ -429,7 +432,8 @@ }, { "name": "line_0_1", - "elementIds": [ 2 ], + "type": "cable", + "elementIds": [ 2 ], "materialId": 11, "initialTerminalId": 7, "endTerminalId": 21, @@ -437,7 +441,8 @@ }, { "name": "line_1_1", - "elementIds": [10], + "type": "cable", + "elementIds": [10], "materialId": 3, "initialTerminalId": 7, "endTerminalId": 7, @@ -446,7 +451,8 @@ }, { "name": "line_2_4", - "elementIds": [ 25, 26 ], + "type": "cable", + "elementIds": [ 25, 26 ], "materialId": 62, "initialTerminalId": 72, "endTerminalId": 8, @@ -454,14 +460,16 @@ }, { "name": "line_0_2", - "elementIds": [ 3 ], + "type": "cable", + "elementIds": [ 3 ], "materialId": 12, "initialTerminalId": 7, "endTerminalId": 20 }, { "name": "line_1_2", - "elementIds": [ 11 ], + "type": "cable", + "elementIds": [ 11 ], "materialId": 4, "initialTerminalId": 7, "endTerminalId": 7, @@ -469,7 +477,8 @@ }, { "name": "line_2_5", - "elementIds": [ 27, 28, 29, 30, 31, 32 ], + "type": "cable", + "elementIds": [ 27, 28, 29, 30, 31, 32 ], "materialId": 63, "initialTerminalId": 76, "endTerminalId": 86, diff --git a/testData/input_examples/sgbc.fdtd.json b/testData/input_examples/sgbc.fdtd.json index 2ffb5130..63c0cf48 100644 --- a/testData/input_examples/sgbc.fdtd.json +++ b/testData/input_examples/sgbc.fdtd.json @@ -51,7 +51,8 @@ "materialAssociations": [ { - "materialId": 1, + "type": "bulk", + "materialId": 1, "elementIds": [ 1 ] }, { diff --git a/testData/input_examples/shieldedPair.fdtd.json b/testData/input_examples/shieldedPair.fdtd.json index fa9e584c..6459d1fd 100644 --- a/testData/input_examples/shieldedPair.fdtd.json +++ b/testData/input_examples/shieldedPair.fdtd.json @@ -167,21 +167,24 @@ "materialAssociations": [ { "name": "line_0", - "elementIds": [ 1 ], + "type": "cable", + "elementIds": [ 1 ], "materialId": 2, "initialTerminalId": 6, "endTerminalId": 6 }, { "name": "line_1", - "elementIds": [ 6,7 ], + "type": "cable", + "elementIds": [ 6,7 ], "materialId": 1, "initialTerminalId": 3, "endTerminalId": 3, "containedWithinElementId": 1 }, { - "materialId" : 5, + "type": "bulk", + "materialId" : 5, "elementIds": [5] } diff --git a/testData/input_examples/sphere.fdtd.json b/testData/input_examples/sphere.fdtd.json index 2690a2b2..3f306146 100644 --- a/testData/input_examples/sphere.fdtd.json +++ b/testData/input_examples/sphere.fdtd.json @@ -40903,7 +40903,8 @@ ], "materialAssociations": [ { - "materialId": 1, + "type": "surface", + "materialId": 1, "elementIds": [ 3 ] diff --git a/testData/input_examples/thinSlot.fdtd.json b/testData/input_examples/thinSlot.fdtd.json index 2990fe2a..510190bc 100644 --- a/testData/input_examples/thinSlot.fdtd.json +++ b/testData/input_examples/thinSlot.fdtd.json @@ -49,8 +49,8 @@ ], "materialAssociations": [ - { "materialId": 1, "elementIds": [4]}, - { "materialId": 2, "elementIds": [5]} + {"type": "bulk", "materialId": 1, "elementIds": [4]}, + {"type": "line", "materialId": 2, "elementIds": [5]} ], "sources": [ diff --git a/testData/input_examples/towelHanger.fdtd.json b/testData/input_examples/towelHanger.fdtd.json index cf52f6fa..108676f7 100644 --- a/testData/input_examples/towelHanger.fdtd.json +++ b/testData/input_examples/towelHanger.fdtd.json @@ -69,14 +69,16 @@ "materialAssociations": [ { - "name": "wire", + "type": "cable", + "name": "wire", "materialId": 1, "initialTerminalId": 2, "endTerminalId": 3, "elementIds": [2] }, { - "materialId" : 4, + "type": "bulk", + "materialId" : 4, "elementIds": [3] } ],