!
! This file is part of SACAMOS, State of the Art CAble MOdels in Spice.
! It was developed by the University of Nottingham and the Netherlands Aerospace
! Centre (NLR) for ESA under contract number 4000112765/14/NL/HK.
!
! Copyright (C) 2016-2017 University of Nottingham
!
! SACAMOS is free software: you can redistribute it and/or modify it under the
! terms of the GNU General Public License as published by the Free Software
! Foundation, either version 3 of the License, or (at your option) any later
! version.
!
! SACAMOS is distributed in the hope that it will be useful, but
! WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
! or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
! for more details.
!
! A copy of the GNU General Public License version 3 can be found in the
! file GNU_GPL_v3 in the root or at .
!
! SACAMOS uses the EISPACK library (in /SRC/EISPACK). EISPACK is subject to
! the GNU Lesser General Public License. A copy of the GNU Lesser General Public
! License version can be found in the file GNU_LGPL in the root of EISPACK
! (/SRC/EISPACK ) or at .
!
! The University of Nottingham can be contacted at: ggiemr@nottingham.ac.uk
!
! File Contents:
! MODULE cable_bundle_module
! CONTAINS
! SUBROUTINE read_cable_bundle
! SUBROUTINE write_cable_bundle
! SUBROUTINE deallocate_cable_bundle
! SUBROUTINE check_cables_wrt_ground_plane
! SUBROUTINE check_cable_intersections
!
! NAME
! MODULE cable_bundle_module
!
! Data strunctures and subroutines relating to cable bundles
!
! COMMENTS
! Need to improve error handling in file reading
! Not sure that some arrays in the type_specification need to be in this structure as they are only used in one subroutine...
!
! HISTORY
! started 25/11/2015 CJS
! stage 3 developments started 21/3/2015 CJS
! generalise conductor impedance for transfer impedance model (stage 5) CJS 12/5/2016
! CJS 25/08/2016 updates for revised transfer impedance and conductor impedance model for shields
! 16/11/2017 CJS Include network synthesis process to replace s-domain transfer functions
!
MODULE cable_bundle_module
USE type_specifications
USE cable_module
IMPLICIT NONE
! This is a general structure used to hold conductor based lists,
TYPE::conductor_list_type
integer :: n_elements
integer,allocatable :: element(:)
END TYPE conductor_list_type
! This is the main structure used to hold all the bundle information
TYPE::bundle_specification_type
character(LEN=line_length) :: version
character(LEN=line_length) :: bundle_name
integer :: tot_n_conductors
integer :: tot_n_shielded_conductors
integer :: tot_n_external_conductors
! dimension of the global matrix system (total number of conductors-1)
integer :: system_dimension
! cable information, total number of cables including and excluding the ground plane (if it exists)
integer :: n_cables
integer :: n_cables_without_ground_plane
! Array of cable specification data for all the cables in this bundle
type(cable_specification_type),allocatable :: cable(:)
! list of cable positions in the bundle cross section and rotation angles
real(dp),allocatable :: cable_x_offset(:)
real(dp),allocatable :: cable_y_offset(:)
real(dp),allocatable :: cable_angle(:)
! ground plane information: note we have two notations at the moment.
! This will need to be sorted out and one only adopted
logical :: ground_plane_present
real(dp) :: ground_plane_angle
real(dp) :: ground_plane_offset
real(dp) :: ground_plane_x,ground_plane_y,ground_plane_theta
real(dp) :: ground_plane_nx,ground_plane_ny
integer :: ground_plane_cable_side ! +1 if the cables are on the normal direction side of the ground plane, -1 otherwise
! domain based information
integer :: tot_n_domains
integer,allocatable :: n_conductors(:) ! number of conductors in each domain
type(conductor_list_type),allocatable :: terminal_conductor_list(:) ! external conductor number for coonductors in each domain
type(matrix),allocatable :: L(:) ! 'high frequency' inductance matrix for each domain
type(matrix),allocatable :: C(:) ! 'high frequency' capacitance matrix for each domain
type(Sfilter_matrix),allocatable :: Z(:) ! frequency dependent impedance matrix for each domain
type(Sfilter_matrix),allocatable :: Y(:) ! frequency dependent admittance matrix for each domain
! global conductor based information
type(matrix) :: global_MI ! global domain current transformation matrix
type(matrix) :: global_MV ! global domain voltage transformation matrix
type(matrix) :: global_L ! global 'high frequency' inductance matrix
type(matrix) :: global_C ! global 'high frequency' capacitance matrix
type(Sfilter_matrix) :: global_Z ! global frequency dependent impedance matrix
type(Sfilter_matrix) :: global_Y ! global frequency dependent admittance matrix
! global conductor impedance model information for each conductor
type(conductor_impedance_model),allocatable :: conductor_impedance(:)
! global conductor position in the bundle cross-section
real(dp),allocatable :: conductor_x_offset(:)
real(dp),allocatable :: conductor_y_offset(:)
! arrays for cross referecing numbering information from the global (external) conductor numbering and the domain based numbering systems
logical,allocatable :: terminal_conductor_is_shield_flag(:)
integer,allocatable :: terminal_conductor_to_inner_domain(:)
integer,allocatable :: terminal_conductor_to_outer_domain(:)
integer,allocatable :: terminal_conductor_to_global_domain_conductor(:)
integer,allocatable :: terminal_conductor_to_local_domain_conductor(:)
integer,allocatable :: terminal_conductor_to_reference_terminal_conductor(:)
! Y matrix element function fitting information for frequency dependent dielectrics
! model order for filter fitting
integer :: Y_fit_model_order
! frequency range specification
type(frequency_specification) :: Y_fit_freq_spec
character(LEN=line_length),allocatable :: conductor_label(:)
END TYPE bundle_specification_type
CONTAINS
! The following subroutines apply to all bundles and cable types
! NAME
! SUBROUTINE read_cable_bundle(unit)
!
! read cable bundle structure from a specified unit
!
! COMMENTS
!
!
! HISTORY
! started 2/12/2015 CJS
! stage 3 developments started 21/3/2015 CJS
! generalise conductor impedance for transfer impedance model (stage 5) CJS 12/5/2016
!
SUBROUTINE read_cable_bundle(bundle,file_unit)
USE type_specifications
USE constants
USE general_module
USE cable_module
USE maths
IMPLICIT NONE
! variables passed to subroutine
type(bundle_specification_type),intent(INOUT) :: bundle
integer ,intent(IN) :: file_unit
! local variables
character(len=filename_length) :: filename
logical :: file_exists
character(len=line_length) :: line
integer :: cable
integer :: n_domains
integer :: domain
integer :: matrix_dimension
integer :: n_conductors
integer :: conductor
integer :: ierr
! START
! Open the (.bundle) file to read
filename=trim(MOD_bundle_lib_dir)//trim(bundle%bundle_name)//bundle_file_extn
inquire(file=trim(filename),exist=file_exists)
if (.NOT.file_exists) then
run_status='ERROR, Cannot find the required bundle file:'//trim(filename)
CALL write_program_status()
STOP 1
end if
open(unit=file_unit,file=trim(filename))
if (verbose) write(*,*)'Opened file:',trim(filename)
! read .bundle file
read(file_unit,'(A)',ERR=9000)bundle%version
read(file_unit,'(A)',ERR=9000)bundle%bundle_name
! read cable information
read(file_unit,*,ERR=9000)bundle%n_cables_without_ground_plane
read(file_unit,*,ERR=9000)bundle%n_cables
! allocate and read cable information and cable positions in bundle
ALLOCATE( bundle%cable(1:bundle%n_cables) )
ALLOCATE( bundle%cable_x_offset(1:bundle%n_cables) )
ALLOCATE( bundle%cable_y_offset(1:bundle%n_cables) )
ALLOCATE( bundle%cable_angle(1:bundle%n_cables) )
do cable=1,bundle%n_cables_without_ground_plane
read(file_unit,'(A)')bundle%cable(cable)%cable_name
CALL read_cable(bundle%cable(cable),cable_file_unit)
read(file_unit,*,ERR=9000)bundle%cable_x_offset(cable),bundle%cable_y_offset(cable),bundle%cable_angle(cable)
! convert angle to radians
bundle%cable_angle(cable)=bundle%cable_angle(cable)*pi/180d0
end do ! next cable
! read ground plane specification
read(file_unit,'(A)',IOSTAT=ierr)line
if (ierr.NE.0) then
run_status='ERROR reading ground plane present/ absent information'
CALL write_program_status()
STOP 1
end if
CALL convert_to_lower_case(line,line_length)
bundle%ground_plane_present=(line.eq.'ground_plane')
if (bundle%ground_plane_present) then
read(file_unit,*,IOSTAT=ierr)bundle%ground_plane_x,bundle%ground_plane_y,bundle%ground_plane_angle
read(file_unit,*,IOSTAT=ierr)bundle%ground_plane_nx,bundle%ground_plane_ny
read(file_unit,*,IOSTAT=ierr)bundle%ground_plane_cable_side
if (ierr.NE.0) then
run_status='ERROR reading ground plane position and angle'
CALL write_program_status()
STOP 1
end if
! convert ground plane angle to radians
bundle%ground_plane_angle=bundle%ground_plane_angle*pi/180d0
! calculate offset
bundle%ground_plane_offset=-bundle%ground_plane_x*sin(bundle%ground_plane_angle)+ &
bundle%ground_plane_y*cos(bundle%ground_plane_angle)
! set the geometric data for the last cable in the list i.e. the ground plane
cable=bundle%n_cables
bundle%cable_x_offset(cable)=bundle%ground_plane_x
bundle%cable_y_offset(cable)=bundle%ground_plane_y
bundle%cable_angle(cable)=bundle%ground_plane_angle-pi/2d0 ! note there are two ground plane spec formats at the moment...
else
! set x, y, angle and offset to 0
bundle%ground_plane_x=0d0
bundle%ground_plane_y=0d0
bundle%ground_plane_nx=0d0
bundle%ground_plane_ny=0d0
bundle%ground_plane_cable_side=0
bundle%ground_plane_angle=0d0
bundle%ground_plane_offset=0d0
end if
! read system dimension information
read(file_unit,*)bundle%tot_n_conductors
read(file_unit,*)bundle%tot_n_external_conductors
read(file_unit,*)bundle%system_dimension
! read domain information
read(file_unit,*,ERR=9000)bundle%tot_n_domains
ALLOCATE( bundle%n_conductors(1:bundle%tot_n_domains) )
ALLOCATE( bundle%L(1:bundle%tot_n_domains) )
ALLOCATE( bundle%C(1:bundle%tot_n_domains) )
ALLOCATE( bundle%Z(1:bundle%tot_n_domains))
ALLOCATE( bundle%Y(1:bundle%tot_n_domains))
ALLOCATE( bundle%terminal_conductor_list(1:bundle%tot_n_domains))
n_domains=bundle%tot_n_domains
do domain=1,bundle%tot_n_domains
read(file_unit,*,ERR=9000) ! comment line
read(file_unit,*)bundle%n_conductors(domain)
read(file_unit,*,ERR=9000) ! comment line
read(file_unit,*,ERR=9000)bundle%terminal_conductor_list(domain)%n_elements
ALLOCATE( bundle%terminal_conductor_list(domain)%element(1:bundle%terminal_conductor_list(domain)%n_elements) )
do conductor=1,bundle%terminal_conductor_list(domain)%n_elements
read(file_unit,*,ERR=9000)bundle%terminal_conductor_list(domain)%element(conductor)
end do
read(file_unit,*,ERR=9000) ! comment line
read(file_unit,*)matrix_dimension
bundle%L(domain)%dim=matrix_dimension
ALLOCATE( bundle%L(domain)%mat(1:matrix_dimension,1:matrix_dimension) )
CALL dread_matrix(bundle%L(domain)%mat,matrix_dimension,matrix_dimension,matrix_dimension,file_unit)
write(*,*)'L='
CALL dwrite_matrix(bundle%L(domain)%mat,matrix_dimension,matrix_dimension,matrix_dimension,0) ! ******
read(file_unit,*,ERR=9000) ! comment line
read(file_unit,*)matrix_dimension
bundle%C(domain)%dim=matrix_dimension
ALLOCATE( bundle%C(domain)%mat(1:matrix_dimension,1:matrix_dimension) )
CALL dread_matrix(bundle%C(domain)%mat,matrix_dimension,matrix_dimension,matrix_dimension,file_unit)
write(*,*)'C='
CALL dwrite_matrix(bundle%C(domain)%mat,matrix_dimension,matrix_dimension,matrix_dimension,0) ! ******
read(file_unit,*,ERR=9000) ! comment line
CALL read_Sfilter_matrix( bundle%Z(domain),file_unit )
read(file_unit,*,ERR=9000) ! comment line
CALL read_Sfilter_matrix( bundle%Y(domain),file_unit )
end do
read(file_unit,*,ERR=9000) ! comment line
read(file_unit,*)matrix_dimension
bundle%global_MI%dim=matrix_dimension
ALLOCATE( bundle%global_MI%mat(1:matrix_dimension,1:matrix_dimension) )
CALL dread_matrix(bundle%global_MI%mat,matrix_dimension,matrix_dimension,matrix_dimension,file_unit)
read(file_unit,*,ERR=9000) ! comment line
read(file_unit,*)matrix_dimension
bundle%global_MV%dim=matrix_dimension
ALLOCATE( bundle%global_MV%mat(1:matrix_dimension,1:matrix_dimension) )
CALL dread_matrix(bundle%global_MV%mat,matrix_dimension,matrix_dimension,matrix_dimension,file_unit)
read(file_unit,*,ERR=9000) ! comment line
read(file_unit,*)matrix_dimension
bundle%global_L%dim=matrix_dimension
ALLOCATE( bundle%global_L%mat(1:matrix_dimension,1:matrix_dimension) )
CALL dread_matrix(bundle%global_L%mat,matrix_dimension,matrix_dimension,matrix_dimension,file_unit)
read(file_unit,*,ERR=9000) ! comment line
read(file_unit,*)matrix_dimension
bundle%global_C%dim=matrix_dimension
ALLOCATE( bundle%global_C%mat(1:matrix_dimension,1:matrix_dimension) )
CALL dread_matrix(bundle%global_C%mat,matrix_dimension,matrix_dimension,matrix_dimension,file_unit)
read(file_unit,*,ERR=9000) ! comment line
CALL read_Sfilter_matrix( bundle%global_Z,file_unit )
read(file_unit,*,ERR=9000) ! comment line
CALL read_Sfilter_matrix( bundle%global_Y,file_unit )
! read the loss model information for each conductor
ALLOCATE( bundle%conductor_impedance(1:bundle%tot_n_conductors) )
read(file_unit,*) ! comment line
do conductor=1,bundle%tot_n_conductors
CALL read_conductor_impedance_model(bundle%conductor_impedance(conductor),file_unit)
end do
! read the x and y position for each conductor: this is needed for incident field excitation
ALLOCATE( bundle%conductor_x_offset(1:bundle%tot_n_conductors) )
ALLOCATE( bundle%conductor_y_offset(1:bundle%tot_n_conductors) )
read(file_unit,*) ! comment line
do conductor=1,bundle%tot_n_conductors
read(file_unit,*)bundle%conductor_x_offset(conductor),bundle%conductor_y_offset(conductor)
end do
! numbering information
read(file_unit,*) ! comment line
ALLOCATE( bundle%terminal_conductor_is_shield_flag(1:bundle%tot_n_conductors) )
ALLOCATE( bundle%terminal_conductor_to_inner_domain(1:bundle%tot_n_conductors) )
ALLOCATE( bundle%terminal_conductor_to_outer_domain(1:bundle%tot_n_conductors) )
ALLOCATE( bundle%terminal_conductor_to_global_domain_conductor(1:bundle%tot_n_conductors) )
ALLOCATE( bundle%terminal_conductor_to_local_domain_conductor(1:bundle%tot_n_conductors) )
ALLOCATE( bundle%terminal_conductor_to_reference_terminal_conductor(1:bundle%tot_n_conductors) )
do conductor=1,bundle%tot_n_conductors
read(file_unit,*)bundle%terminal_conductor_is_shield_flag(conductor), &
bundle%terminal_conductor_to_inner_domain(conductor), &
bundle%terminal_conductor_to_outer_domain(conductor), &
bundle%terminal_conductor_to_global_domain_conductor(conductor), &
bundle%terminal_conductor_to_local_domain_conductor(conductor), &
bundle%terminal_conductor_to_reference_terminal_conductor(conductor)
end do
! read the conductor labels
ALLOCATE( bundle%conductor_label(1:bundle%tot_n_conductors) )
read(file_unit,*) ! comment line
do conductor=1,bundle%tot_n_conductors
read(file_unit,'(A)')bundle%conductor_label(conductor)
end do
! close .bundle file
CLOSE(unit=file_unit)
if (verbose) write(*,*)'Closed file:',trim(filename)
RETURN
9000 run_status='ERROR reading the bundle file:'//trim(filename)
CALL write_program_status()
STOP 1
END SUBROUTINE read_cable_bundle
! NAME
! SUBROUTINE write_cable_bundle
!
! write the cable bundle structure to a specified unit
!
! COMMENTS
!
!
! HISTORY
! started 2/12/2015 CJS
! stage 3 developments started 21/3/2015 CJS
! generalise conductor impedance for transfer impedance model (stage 5) CJS 12/5/2016
!
SUBROUTINE write_cable_bundle(bundle,file_unit)
USE type_specifications
USE constants
USE general_module
USE cable_module
USE maths
IMPLICIT NONE
! variables passed to subroutine
type(bundle_specification_type),intent(INOUT) :: bundle
integer,intent(IN) :: file_unit
! local variables
character(len=filename_length) :: filename
character(len=line_length) :: line
integer :: cable
integer :: domain
integer :: matrix_dimension
integer :: conductor
integer :: n_cables_to_write
! START
! Open the output (.bundle) file
filename=trim(MOD_bundle_lib_dir)//trim(bundle%bundle_name)//bundle_file_extn
open(unit=file_unit,file=trim(filename))
! write .bundle file
write(file_unit,'(A)')trim(bundle%version)
write(file_unit,'(A)')trim(bundle%bundle_name)
write(file_unit,*)bundle%n_cables_without_ground_plane,' ! number of cables not including ground plane'
write(file_unit,*)bundle%n_cables,' ! number of cables, cable name and x y coordinates follow...'
! write cable names and coordinates
do cable=1,bundle%n_cables_without_ground_plane
write(file_unit,'(A)')trim(bundle%cable(cable)%cable_name)
write(file_unit,*)bundle%cable_x_offset(cable),bundle%cable_y_offset(cable), &
bundle%cable_angle(cable),' x y coordinates and angle of cable '
end do ! next cable
! write ground plane specification
if (bundle%ground_plane_present) then
write(file_unit,'(A)')'ground_plane'
! note: convert angle back to degrees
write(file_unit,*)bundle%ground_plane_x,bundle%ground_plane_y,bundle%ground_plane_angle*180d0/pi, &
' x y coordinates and angle of ground plane '
write(file_unit,*)bundle%ground_plane_nx,bundle%ground_plane_ny,' ground plane normal direction'
write(file_unit,*)bundle%ground_plane_cable_side,' orientation of cables wrt ground plane'
else
write(file_unit,'(A)')'no_ground_plane'
end if
write(file_unit,*)bundle%tot_n_conductors,' # total number of conductors'
write(file_unit,*)bundle%tot_n_external_conductors,' # total number of external conductors'
write(file_unit,*)bundle%system_dimension,' # dimension of the matrix system characterising the MTL propagation'
write(file_unit,*)bundle%tot_n_domains,' # number of domains'
do domain=1,bundle%tot_n_domains
write(file_unit,*)'Domain number',domain
write(file_unit,*)bundle%n_conductors(domain),' number of conductors in this domain'
write(file_unit,*)'terminal_conductor_list'
write(file_unit,*)bundle%terminal_conductor_list(domain)%n_elements,' ! number of elements '
do conductor=1,bundle%terminal_conductor_list(domain)%n_elements
write(file_unit,*)bundle%terminal_conductor_list(domain)%element(conductor)
end do
matrix_dimension=bundle%L(domain)%dim
write(file_unit,*)'Per-Unit-length Inductance Matrix, [L]'
write(file_unit,*)matrix_dimension,' Dimension of [L]'
CALL dwrite_matrix(bundle%L(domain)%mat,matrix_dimension,matrix_dimension,matrix_dimension,file_unit)
write(file_unit,*)'Per-Unit-length Capacitance Matrix, [C]'
write(file_unit,*)matrix_dimension,' Dimension of [C]'
CALL dwrite_matrix(bundle%C(domain)%mat,matrix_dimension,matrix_dimension,matrix_dimension,file_unit)
write(file_unit,*)'Per-Unit-length Impedance Matrix, Z'
CALL write_Sfilter_matrix( bundle%Z(domain),file_unit )
write(file_unit,*)'Per-Unit-length Admittance Matrix, Y'
CALL write_Sfilter_matrix( bundle%Y(domain),file_unit )
end do
write(file_unit,*)'# Global current domain transformation matrix, [MI]'
matrix_dimension=bundle%global_MI%dim-1
write(file_unit,*)matrix_dimension,' Dimension of [MI]'
CALL dwrite_matrix(bundle%global_MI%mat,matrix_dimension,matrix_dimension,bundle%global_MI%dim,file_unit)
write(file_unit,*)'# Global voltage domain transformation matrix, [MV]'
matrix_dimension=bundle%global_MV%dim-1
write(file_unit,*)matrix_dimension,' Dimension of [MV]'
CALL dwrite_matrix(bundle%global_MV%mat,matrix_dimension,matrix_dimension,bundle%global_MI%dim,file_unit)
write(file_unit,*)'# Global domain based inductance matrix, [L]'
matrix_dimension=bundle%global_L%dim
write(file_unit,*)matrix_dimension,' Dimension of [L]'
CALL dwrite_matrix(bundle%global_L%mat,matrix_dimension,matrix_dimension,matrix_dimension,file_unit)
write(file_unit,*)'# Global domain based capacitance matrix, [C]'
matrix_dimension=bundle%global_C%dim
write(file_unit,*)matrix_dimension,' Dimension of [C]'
CALL dwrite_matrix(bundle%global_C%mat,matrix_dimension,matrix_dimension,matrix_dimension,file_unit)
write(file_unit,*)'Global domain based Per-Unit-length Impedance Matrix, Z'
CALL write_Sfilter_matrix( bundle%global_Z,file_unit )
write(file_unit,*)'Global domain based Per-Unit-length Admittance Matrix, Y'
CALL write_Sfilter_matrix( bundle%global_Y,file_unit )
! write the loss model information for each conductor
write(file_unit,*)' # conductor impedance models'
do conductor=1,bundle%tot_n_conductors
CALL write_conductor_impedance_model(bundle%conductor_impedance(conductor),file_unit)
end do
! write the x and y position for each conductor: this is needed for incident field excitation
write(file_unit,*)' # conductor x y positions'
do conductor=1,bundle%tot_n_conductors
write(file_unit,*)bundle%conductor_x_offset(conductor),bundle%conductor_y_offset(conductor)
end do
! numbering information
write(file_unit,'(A)')'is_shield tc_to_in_domain tc_to_out_domain tc_to_gdc tc_to_ldc tc_to_ref_tc '
do conductor=1,bundle%tot_n_conductors
write(file_unit,8000)bundle%terminal_conductor_is_shield_flag(conductor), &
bundle%terminal_conductor_to_inner_domain(conductor), &
bundle%terminal_conductor_to_outer_domain(conductor), &
bundle%terminal_conductor_to_global_domain_conductor(conductor), &
bundle%terminal_conductor_to_local_domain_conductor(conductor), &
bundle%terminal_conductor_to_reference_terminal_conductor(conductor)
8000 format(L5,5I15)
end do
! write the conductor labels
write(file_unit,*)' # Conductor labels'
do conductor=1,bundle%tot_n_conductors
write(file_unit,*)trim(bundle%conductor_label(conductor))
end do
! close .bundle file
CLOSE(unit=file_unit)
RETURN
END SUBROUTINE write_cable_bundle
! NAME
! SUBROUTINE deallocate_cable_bundle
!
! deallocate cable_bundle structure data
!
! COMMENTS
!
!
! HISTORY
! started 2/12/2015 CJS
! generalise conductor impedance for transfer impedance model (stage 5) CJS 12/5/2016
!
SUBROUTINE deallocate_cable_bundle(bundle)
USE type_specifications
USE general_module
USE cable_module
IMPLICIT NONE
! variables passed to subroutine
type(bundle_specification_type),intent(INOUT) :: bundle
! local variables
integer :: cable
integer :: domain
integer :: conductor
! START
do cable=1,bundle%n_cables
CALL deallocate_cable(bundle%cable(cable))
end do
if (allocated(bundle%cable)) DEALLOCATE( bundle%cable )
if (allocated(bundle%cable_x_offset )) DEALLOCATE( bundle%cable_x_offset )
if (allocated(bundle%cable_y_offset )) DEALLOCATE( bundle%cable_y_offset )
if (allocated(bundle%cable_angle )) DEALLOCATE( bundle%cable_angle )
if (allocated(bundle%n_conductors )) DEALLOCATE( bundle%n_conductors )
if (allocated(bundle%terminal_conductor_list )) then
do domain=1,bundle%tot_n_domains
if (allocated(bundle%terminal_conductor_list(domain)%element )) &
DEALLOCATE( bundle%terminal_conductor_list(domain)%element )
end do
DEALLOCATE( bundle%terminal_conductor_list )
end if
if (allocated(bundle%L )) then
do domain=1,bundle%tot_n_domains
if (allocated(bundle%L(domain)%mat )) DEALLOCATE( bundle%L(domain)%mat )
end do
DEALLOCATE( bundle%L )
end if
if (allocated(bundle%C )) then
do domain=1,bundle%tot_n_domains
if (allocated(bundle%C(domain)%mat )) DEALLOCATE( bundle%C(domain)%mat )
end do
DEALLOCATE( bundle%C )
end if
if (ALLOCATED(bundle%Z)) then
do domain=1,bundle%tot_n_domains
CALL deallocate_Sfilter_matrix( bundle%Z(domain) )
end do
DEALLOCATE(bundle%Z)
end if
if (ALLOCATED(bundle%Y)) then
do domain=1,bundle%tot_n_domains
CALL deallocate_Sfilter_matrix( bundle%Y(domain) )
end do
DEALLOCATE(bundle%Y)
end if
if (allocated(bundle%global_MI%mat)) DEALLOCATE( bundle%global_MI%mat )
if (allocated(bundle%global_MV%mat)) DEALLOCATE( bundle%global_MV%mat )
if (allocated(bundle%global_L%mat)) DEALLOCATE( bundle%global_L%mat )
if (allocated(bundle%global_C%mat)) DEALLOCATE( bundle%global_C%mat )
CALL deallocate_Sfilter_matrix( bundle%global_Z )
CALL deallocate_Sfilter_matrix( bundle%global_Y )
if (ALLOCATED(bundle%conductor_impedance)) then
do conductor=1,bundle%tot_n_conductors
CALL deallocate_conductor_impedance_model(bundle%conductor_impedance(conductor))
end do
DEALLOCATE(bundle%conductor_impedance)
end if
if (ALLOCATED( bundle%conductor_x_offset )) DEALLOCATE( bundle%conductor_x_offset )
if (ALLOCATED( bundle%conductor_y_offset )) DEALLOCATE( bundle%conductor_y_offset )
! Numbering information required for transfer impedance calculation
if(ALLOCATED( bundle%terminal_conductor_is_shield_flag )) DEALLOCATE( bundle%terminal_conductor_is_shield_flag )
if(ALLOCATED( bundle%terminal_conductor_to_inner_domain )) DEALLOCATE( bundle%terminal_conductor_to_inner_domain )
if(ALLOCATED( bundle%terminal_conductor_to_outer_domain )) DEALLOCATE( bundle%terminal_conductor_to_outer_domain )
if(ALLOCATED( bundle%terminal_conductor_to_global_domain_conductor )) &
DEALLOCATE( bundle%terminal_conductor_to_global_domain_conductor )
if(ALLOCATED( bundle%terminal_conductor_to_local_domain_conductor )) &
DEALLOCATE( bundle%terminal_conductor_to_local_domain_conductor )
if(ALLOCATED( bundle%terminal_conductor_to_reference_terminal_conductor )) &
DEALLOCATE( bundle%terminal_conductor_to_reference_terminal_conductor )
if (ALLOCATED( bundle%conductor_label )) then
DEALLOCATE(bundle%conductor_label)
end if
RETURN
END SUBROUTINE deallocate_cable_bundle
!
! NAME
! SUBROUTINE check_cables_wrt_ground_plane
!
! check that the cables are all on one side of the ground plane to ensure consistency
! and indicate which side the cables are on by setting bundle%ground_plane_cable_side
!
! COMMENTS
!
!
! HISTORY
! started 29/06/2016 CJS
!
SUBROUTINE check_cables_wrt_ground_plane(bundle)
USE type_specifications
USE general_module
USE cable_module
IMPLICIT NONE
! variables passed to subroutine
type(bundle_specification_type),intent(INOUT) :: bundle
! local variables
integer :: cable
real(dp) :: norm_x,norm_y
real(dp) :: p
real(dp) :: gp_offset
real(dp) :: gp_offset_cable_1
! START
! calculate the ground plane normal direction
norm_x=bundle%ground_plane_nx
norm_y=bundle%ground_plane_ny
! The equation of the ground plane is r.norm-P=0, calculate P here
P=bundle%ground_plane_x*norm_x+bundle%ground_plane_y*norm_y
! loop over all of the cables, calculating the offset from the ground plane in the normal direction
! offset=r.norm-P, and check that all offsets have the same sign
if (verbose) then
write(*,*)'Checking the orientation of cables wrt the ground plane'
write(*,*)'GP normal:',norm_x,norm_y
write(*,*)'GP offset:',bundle%ground_plane_x+bundle%ground_plane_y
write(*,*)'P=',P
end if
do cable=1,bundle%n_cables_without_ground_plane
gp_offset=bundle%cable_x_offset(cable)*norm_x+bundle%cable_y_offset(cable)*norm_y-P
if (verbose) then
write(*,*)'Cable',cable,' offset',gp_offset
end if
if (cable.EQ.1) then
gp_offset_cable_1=gp_offset
else
! check consistency of ground plane offsets
if (gp_offset_cable_1*gp_offset.LE.0d0) then
run_status='ERROR there are cables both sides of the ground plane'
CALL write_program_status()
STOP 1
end if
end if ! cable.NE.1
end do ! next cable to check
if (gp_offset_cable_1.GT.0d0) then
bundle%ground_plane_cable_side=1
else
bundle%ground_plane_cable_side=-1
end if
RETURN
END SUBROUTINE check_cables_wrt_ground_plane
!
! NAME
! SUBROUTINE check_cable_intersections
!
! check that the cables do not intersect
! the intersection test checks intersection of the outer shape of each cable
! which is usually the outer dielectric layer apart from overshields or D connectors which
! are assumed not to have dielectric
!
! COMMENTS
! Revised to work with all cable types
!
! HISTORY
! started 8/10/2016 CJS
!
!
SUBROUTINE check_cable_intersection(bundle)
USE type_specifications
USE general_module
USE cable_module
IMPLICIT NONE
! variables passed to subroutine
type(bundle_specification_type),intent(IN) :: bundle
! local variables
integer :: cable1,cable2
integer :: nec1,nec2,ec1,ec2
integer :: shape1,shape2
integer :: type1,type2
real(dp) :: ox,oy,theta
real(dp) :: r
real(dp) :: wd,hd
integer :: nc,ncrow(2)
real(dp) :: rw,p,s,o,W(2)
integer :: npts1
real(dp),allocatable :: shape1_x(:)
real(dp),allocatable :: shape1_y(:)
integer :: npts2
real(dp),allocatable :: shape2_x(:)
real(dp),allocatable :: shape2_y(:)
logical :: intersect
logical :: intersect2
logical :: nested_1_in_2
logical :: nested_2_in_1
logical :: gp_intersect
logical :: intersection_found
! START
intersection_found=.FALSE.
! loop over cable 1
do cable1=1,bundle%n_cables_without_ground_plane
ox=bundle%cable_x_offset(cable1)
oy=bundle%cable_y_offset(cable1)
theta=bundle%cable_angle(cable1)
type1=bundle%cable(cable1)%cable_type
if ((bundle%cable(cable1)%cable_type.NE.cable_geometry_type_flex_cable).AND. &
(bundle%cable(cable1)%cable_type.NE.cable_geometry_type_ML_flex_cable) ) then
nec1=bundle%cable(cable1)%n_external_conductors
else
nec1=1
end if
! loop over the external conductors of cable 1
do ec1=1,nec1
shape1=bundle%cable(cable1)%external_model(ec1)%conductor_type
! generate a list of points on cable 1 outer surface
if (shape1.EQ.rectangle) then
wd=bundle%cable(cable1)%external_model(1)%dielectric_width
hd=bundle%cable(cable1)%external_model(1)%dielectric_height
CALL generate_rectangle_points(npts1,shape1_x,shape1_y,ox,oy,theta,wd,hd)
else if (shape1.EQ.circle) then
r=bundle%cable(cable1)%external_model(ec1)%dielectric_radius
CALL generate_circle_points(npts1,shape1_x,shape1_y,ox,oy,r)
else if (shape1.EQ.Dshape) then
nc=bundle%cable(cable1)%tot_n_conductors
rw=bundle%cable(cable1)%parameters(1)
p=bundle%cable(cable1)%parameters(2)
s=bundle%cable(cable1)%parameters(3)
o=bundle%cable(cable1)%parameters(4)
ncrow(1)=nc/2
ncrow(2)=(nc-1)-ncrow(1)
w(1)=(ncrow(1)-1)*p
w(2)=(ncrow(2)-1)*p
CALL generate_Dshape_points(npts1,shape1_x,shape1_y,ox,oy,w(1)/2d0,w(2)/2d0,s/2d0,rw+o,theta)
end if
if (bundle%ground_plane_present) then
! check for intersection of the cables with the ground plane
gp_intersect=.FALSE.
if (verbose) write(*,*)'TESTING: intersection of cable',cable1,' with the ground plane'
CALL gptest(npts1,shape1_x,shape1_y,gp_intersect)
if (gp_intersect) then
if (verbose) write(*,*)'Cable ',cable1,' intersects the ground plane'
intersection_found=.TRUE.
end if
end if
! loop over cable 2
do cable2=cable1+1,bundle%n_cables_without_ground_plane
ox=bundle%cable_x_offset(cable2)
oy=bundle%cable_y_offset(cable2)
theta=bundle%cable_angle(cable2)
type2=bundle%cable(cable2)%cable_type
if ((bundle%cable(cable1)%cable_type.NE.cable_geometry_type_flex_cable).AND. &
(bundle%cable(cable1)%cable_type.NE.cable_geometry_type_ML_flex_cable) ) then
nec2=bundle%cable(cable2)%n_external_conductors
else
nec2=1
end if
! loop over the external conductors of cable 2
do ec2=1,nec2
shape2=bundle%cable(cable2)%external_model(ec2)%conductor_type
! generate a list of points on cable 1 outer surface
if (shape2.EQ.rectangle) then
wd=bundle%cable(cable2)%external_model(1)%dielectric_width
hd=bundle%cable(cable2)%external_model(1)%dielectric_height
CALL generate_rectangle_points(npts2,shape2_x,shape2_y,ox,oy,theta,wd,hd)
else if (shape2.EQ.circle) then
r=bundle%cable(cable2)%external_model(ec2)%dielectric_radius
CALL generate_circle_points(npts2,shape2_x,shape2_y,ox,oy,r)
else if (shape2.EQ.Dshape) then
nc=bundle%cable(cable2)%tot_n_conductors
rw=bundle%cable(cable2)%parameters(1)
p=bundle%cable(cable2)%parameters(2)
s=bundle%cable(cable2)%parameters(3)
o=bundle%cable(cable2)%parameters(4)
ncrow(1)=nc/2
ncrow(2)=(nc-1)-ncrow(1)
w(1)=(ncrow(1)-1)*p
w(2)=(ncrow(2)-1)*p
CALL generate_Dshape_points(npts2,shape2_x,shape2_y,ox,oy,w(1)/2d0,w(2)/2d0,s/2d0,rw+o,theta)
end if
! assume that there is no intersection and the shapes are not nested
intersect=.FALSE.
nested_1_in_2=.FALSE.
nested_2_in_1=.FALSE.
! check for the intersection of cable 1 with cable 2 and flag if cable 1 is nested within cable 2.
if (verbose) write(*,*)'TESTING: intersection of cable',cable1,' with cable ',cable2
CALL shape_test(npts1,shape1_x,shape1_y,npts2,shape2_x,shape2_y,intersect,nested_1_in_2)
if (intersect) then
if (verbose) write(*,*)'Cable ',cable1,' intersects Cable',cable2
intersection_found=.TRUE.
end if
! Cables can only be nested if the outer cable is an overshield
if ( nested_1_in_2 ) then
if (type1.NE.cable_geometry_type_overshield) then
if (verbose) write(*,*)'Cable ',cable2,' is inside Cable',cable1
intersection_found=.TRUE.
else
if (verbose) write(*,*)'Cable ',cable2,' is OK inside Overshield Cable',cable1
end if
end if
! check for the intersection of cable 1 with cable 2 and flag if cable 1 is nested within cable 2.
if (verbose) write(*,*)'TESTING: intersection of cable',cable2,' with cable ',cable1
CALL shape_test(npts2,shape2_x,shape2_y,npts1,shape1_x,shape1_y,intersect2,nested_2_in_1)
if (intersect) then
if (verbose) write(*,*)'Cable ',cable2,' intersects Cable',cable1
intersection_found=.TRUE.
end if
! Cables can only be nested if the outer cable is an overshield
if ( nested_2_in_1 ) then
if (type2.NE.cable_geometry_type_overshield) then
if (verbose) write(*,*)'Cable ',cable1,' is inside Cable',cable2
intersection_found=.TRUE.
else
if (verbose) write(*,*)'Cable ',cable1,' is OK inside Overshield Cable',cable2
end if
end if
DEALLOCATE( shape2_x )
DEALLOCATE( shape2_y )
end do ! next external conductor of cable 2
end do ! next cable 2
DEALLOCATE( shape1_x )
DEALLOCATE( shape1_y )
end do ! next external conductor of cable1
end do ! next cable1
if (intersection_found) then
run_status='ERROR there are cables in the bundle which intersect'
CALL write_program_status()
STOP 1
end if
RETURN
END SUBROUTINE check_cable_intersection
!
! NAME
! SUBROUTINE gptest
!
! check that a cable does not intersect the ground plane
!
! COMMENTS
!
!
! HISTORY
! started 20/4/2017 CJS
!
!
SUBROUTINE gptest(npts,shape_x,shape_y,gp_intersect)
USE type_specifications
IMPLICIT NONE
integer,intent(IN) :: npts
real(dp),intent(IN) :: shape_x(npts)
real(dp),intent(IN) :: shape_y(npts)
logical,intent(OUT) :: gp_intersect
! local variables
integer :: i
! START
do i=1,npts
if (shape_y(i).LE.0D0) then
gp_intersect=.TRUE.
RETURN
end if
end do ! next point
RETURN
END SUBROUTINE gptest
!
! NAME
! SUBROUTINE shape_test
!
! check that cables do not intersect, also flag whether the first cable is nested
! i.e. lies entirely within the second
!
! COMMENTS
! We assume that the shape of the cable is convex and that the shape is closed
!
! HISTORY
! started 20/4/2017 CJS
!
!
SUBROUTINE shape_test(npts1,shape1_x,shape1_y,npts2,shape2_x,shape2_y,intersect,nested)
USE type_specifications
IMPLICIT NONE
integer,intent(IN) :: npts1
real(dp),intent(IN) :: shape1_x(npts1)
real(dp),intent(IN) :: shape1_y(npts1)
integer,intent(IN) :: npts2
real(dp),intent(IN) :: shape2_x(npts2)
real(dp),intent(IN) :: shape2_y(npts2)
logical,intent(OUT) :: intersect ! flag to indicate that shapes 1 and 2 intersect
logical,intent(OUT) :: nested ! flag to indicate shape 2 lies within shape 1
! local variables
integer :: i,j
real(dp) :: vx1,vy1
real(dp) :: vx2,vy2
real(dp) :: vp
real(dp) :: dirn
logical :: inside_point_found
logical :: outside_point_found
logical :: local_outside_point_found
! START
intersect=.FALSE.
nested=.FALSE.
inside_point_found=.FALSE.
outside_point_found=.FALSE.
! loop around test points in shape 2
do j=1,npts2
local_outside_point_found=.FALSE.
dirn=0.0 ! set to zero initially to indicate that it is not known
! loop around line segments in shape 1. Note there is one less line segment than the number of points
do i=1,npts1-1
! vector along line segment in shape 1
vx1=shape1_x(i+1)-shape1_x(i)
vy1=shape1_y(i+1)-shape1_y(i)
! vector from first point in line segment to test point
vx2=shape2_x(j)-shape1_x(i)
vy2=shape2_y(j)-shape1_y(i)
! calculate the z component of the vector product of the two vectors
vp=vx1*vy2-vx2*vy1
if (dirn.EQ.0D0) then ! maybe we need to use abs(dirn).LT.small here...
! this is the first value so this sets the direction to test for all other sets of points
dirn=vp
else
! test whether the sign of the direction has changed
if (dirn*vp.LT.0.0) then
! the signs are different then this indicates a test point outside shape 1
local_outside_point_found=.TRUE.
end if ! change in sign of direction
end if ! first test line segment.
end do ! next line segment in shape 1
if (local_outside_point_found) then
outside_point_found=.TRUE.
else
inside_point_found=.TRUE.
end if
end do ! next test point in shape 2
! work out whether we have an intersection
if (inside_point_found.AND.outside_point_found) intersect=.TRUE.
! work out whether we have a nested shape
if (inside_point_found.AND.(.NOT.outside_point_found)) nested=.TRUE.
RETURN
END SUBROUTINE
END MODULE cable_bundle_module