! ! This file is part of SACAMOS, State of the Art CAble MOdels for 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-2018 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 compare_results_data ! CONTAINS ! SUBROUTINE read_compare_results_input_data_file ! SUBROUTINE deallocate_compare_results_data ! PROGRAM compare_results ! ! DESCRIPTION ! ! Software to read two datasets from files and compare them to produce a numerical measure of the difference ! ! The input data is two columns, x and f(x) thus the data could be either time domain or frequency domain (magnitude) data ! the columns for x and f(x) must be specified. ! ! The measure of the difference is calculated as (integral |f1(x)-f2(x)|dx) /(integral dx) where the ! integration is over the range of x for which the data sets overlap. ! ! COMMENTS ! ! ! HISTORY ! ! started 24/11/2015 CJS ! 26/10/2023 CJS don't send exit code 1 if there is an error. This allows results to be plotted using ! the generate_spice_cable_bundle_model process ! ! _________________________________________________________________ ! ! MODULE NAME ! compare_results_data ! ! DESCRIPTION ! ! module containing the following: ! compare_results input data structure ! subroutine to allocate and read this data from a file ! subroutine to deallocate the data structure ! program to calculate the comparison measure. ! ! COMMENTS ! ! ! HISTORY ! ! started 24/11/2015 CJS ! ! MODULE compare_results_data USE type_specifications IMPLICIT NONE ! Structure to hold the data sets for comparison TYPE comparison_dataset integer :: n_samples ! number of data samples real(dp),allocatable :: x(:) ! list of x values real(dp),allocatable :: fx(:) ! list of function of x values real(dp) :: xmin,xmax ! range of x for which data is available END TYPE comparison_dataset CONTAINS ! SUBROUTINE NAME ! read_compare_results_input_data_file ! ! DESCRIPTION ! ! read data from a file into x and fx arrays within the camparison_dataset structure ! return the complete camparison_dataset structure: x and fx arrays and also the min and max x values and number of data samples ! ! COMMENTS ! If the expected data columns cannot be read in then the line is ignored and the process moves on to the next line ! This allows for comment lines in the data files. ! ! HISTORY ! ! started 20/11/2015 CJS ! ! SUBROUTINE read_compare_results_input_data_file(dataset) USE type_specifications USE general_module IMPLICIT NONE ! variables passed to the subroutine type(comparison_dataset),intent(OUT) :: dataset ! local variables character(len=filename_length) :: filename character(len=line_length) :: line logical :: file_exists integer :: xcol,fxcol,maxcol ! columns for x, f(x) and the maximum column number ot be read real(dp),allocatable :: r_in(:) ! array of reals for to read the columns of data into ! temporary local variables integer :: read_loop integer :: sample integer :: comment integer :: i integer :: ierr ! integer to return error codes from file reads ! START write(*,*)'Enter the filename for frequency domain data' read(*,'(A)')filename inquire(file=trim(filename),exist=file_exists) if (.NOT.file_exists) then write(*,*)'Error in compare_results. Cannot find the file:',trim(filename) run_status='ERROR: in read_compare_results_input_data_file, Cannot find the file:'//trim(filename) CALL write_program_status() STOP 1 end if ! open and read the file OPEN(unit=local_file_unit,file=filename) write(*,*)'opened file:',trim(filename) write(*,*)'Enter the column for x data' read(*,*)xcol write(*,*)'Enter the column for f(x) data' read(*,*)fxcol maxcol=max(xcol,fxcol) ALLOCATE( r_in(1:maxcol) ) ! read the file twice, first to count the number of valid samples then allocate data, second to set the frequency and data values do read_loop=1,2 sample=0 comment=0 do ! read the next line of the file into a string read(local_file_unit,'(A)',IOSTAT=ierr)line if (ierr.LT.0) EXIT ! end of file ! try to read a list of numbers from the string read(line,*,IOSTAT=ierr)(r_in(i),i=1,maxcol) if (ierr.eq.0) then ! this looks like a valid line of data so increase the sample number and set the frequency and value (on second read) sample=sample+1 if (read_loop.EQ.2) then dataset%x(sample) =r_in(xcol) dataset%fx(sample)=r_in(fxcol) ! work out the frequency range of the data dataset%xmin=min( dataset%xmin,dataset%x(sample) ) dataset%xmax=max( dataset%xmax,dataset%x(sample) ) end if ! read_loop=2 else ! not a valid data line i.e. a comment comment=comment+1 end if ! comment line end do ! read the next line from the file if (read_loop.EQ.1) then if (sample.LE.1) then write(*,*)'Error in compare_results. No data found in the file:',trim(filename) run_status='ERROR. No data found in the file:'//trim(filename) CALL write_program_status() STOP 1 end if dataset%n_samples=sample ALLOCATE( dataset%x(1:dataset%n_samples) ) ALLOCATE( dataset%fx(1:dataset%n_samples) ) dataset%xmin=1D30 dataset%xmax=-1D30 REWIND(unit=local_file_unit) end if ! read_loop.EQ.1 end do ! next read_loop DEALLOCATE( r_in ) ! close the file CLOSE(unit=local_file_unit) write(*,*)'Number of samples read =',dataset%n_samples write(*,*)'Number of comment lines=',comment END SUBROUTINE read_compare_results_input_data_file ! ! ________________________________________________________________ ! ! ! SUBROUTINE NAME ! deallocate_compare_results_data ! ! DESCRIPTION ! ! deallocate the allocatable arrays in the compare_results_data data structure ! ! COMMENTS ! ! ! HISTORY ! ! started 20/11/2015 CJS ! ! SUBROUTINE deallocate_compare_results_data(dataset) USE type_specifications IMPLICIT NONE ! variables passed to the subroutine type(comparison_dataset),intent(INOUT) :: dataset ! START if (ALLOCATED( dataset%x )) DEALLOCATE ( dataset%x ) if (ALLOCATED( dataset%fx )) DEALLOCATE ( dataset%fx ) END SUBROUTINE deallocate_compare_results_data END MODULE compare_results_data ! ! ________________________________________________________________ ! ! ! ! PROGRAM NAME ! compare_results ! ! DESCRIPTION ! Calculate the comparison measure of the difference between two datasets. ! PROCESS: ! 1. Read the two datasets ! 2. Calculate the x range for which the datasets overlap ! 3. Calculate the measure of the difference between the datasets as (integral |f1(x)-f2(x)|dx) /(integral dx) ! where the integration is over the range of x for which the data sets overlap. ! 4. Write the result to screen and file ! ! COMMENTS ! The integration is based on the x values in dataset 1, the function value from dataset 2 is calculated by linear ! interpolation hence the datasets need not have common x values. ! ! The end points of the integration range needs special treatment maybe to make the process more rigorous. ! ! ! HISTORY ! ! started 20/11/2015 CJS based on compare_results.F90 from the GGI_TLM IELF code (www.github.com/ggiemr/GGI_TLM) ! ! PROGRAM compare_results USE type_specifications USE compare_results_data USE general_module IMPLICIT NONE ! local variables ! frequency domain data to be read from input files type(comparison_dataset) :: dataset1 type(comparison_dataset) :: dataset2 ! filename for the comaprison result character(len=filename_length) :: opfilename ! output quantities real(dp) :: compare_results_value ! range of x for which the datasets overlap i.e. the integration range real(dp) :: xmin_overlap,xmax_overlap integer :: sample_min,sample_max,last_sample,sample real(dp) :: fx_1,fx_2 ! function1 and function 2 values at the current x value real(dp) :: x_1,x_2,x ! x values for function 2 which bracket the current x value - used for interpolation real(dp) :: error ! magnitude of the difference between the function values at the current x value real(dp) :: local_compare_results_value integer :: i integer :: n_samples1,n_samples2 ! number of samples in dataset1 and dataset 2 ! START program_name='compare_results' run_status='Started' CALL write_program_status() CALL read_version() CALL write_license() write(*,*)'compare_results Analysis' write(*,*)' ' ! STAGE 1. read the two datasets to be compared CALL read_compare_results_input_data_file(dataset1) CALL read_compare_results_input_data_file(dataset2) ! STAGE 2. Calculate the overlapping x range write(*,*)'Minimum x in dataset 1=',dataset1%xmin write(*,*)'Minimum x in dataset 2=',dataset2%xmin write(*,*)'Maximum x in dataset 1=',dataset1%xmax write(*,*)'Maximum x in dataset 2=',dataset2%xmax xmin_overlap=max(dataset1%xmin,dataset2%xmin) xmax_overlap=min(dataset1%xmax,dataset2%xmax) write(*,*)'The x range over which the datasets overlap is' write(*,*)'xmin:',xmin_overlap,' Hz, xmax:',xmax_overlap,' Hz' if ((xmax_overlap-xmin_overlap).LE.0D0) then run_status='ERROR: the x ranges of the datasets do not overlap' CALL write_program_status() STOP 1 end if n_samples1=dataset1%n_samples n_samples2=dataset2%n_samples ! loop over samples of dataset1 to work out sample_min and sample_max for local_compare_results_value sample_min=0 sample_max=0 do sample=2,n_samples1-1 if ( ( dataset1%x(sample-1).LE.xmin_overlap ).AND.( sample_min.eq.0 ) ) sample_min=sample if ( ( dataset1%x(sample+1).GE.xmax_overlap ).AND.( sample_max.eq.0 ) ) sample_max=sample end do ! ensure that the sample range is within the array bounds if (sample_min.eq.0) sample_min=2 if (sample_max.eq.0) sample_max=n_samples1-1 write(*,*)'n_samples1 =',n_samples1 write(*,*)'Sample_min=',sample_min,' xmin=',dataset1%x(sample_min) write(*,*)'Sample_max=',sample_max,' xmax=',dataset1%x(sample_max) ! STAGE 3. calculate the difference measure over the full overlap range ! loop over samples in frequency range and do local_compare_results_value calculation local_compare_results_value=0d0 last_sample=1 do sample=sample_min,sample_max fx_1=dataset1%fx(sample) x=dataset1%x(sample) ! find the frequencies which lie either side of f1 and interpolate to give the value from file 2 do i=last_sample,n_samples2-1 x_1=dataset2%x(i) x_2=dataset2%x(i+1) if ( (x_1.le.x).AND. & (x_2.gt.x) ) then ! the required x value is bracketed by x_1 and x_2 so calculate fx_2 using linear interpolation then exit the loop fx_2=dataset2%fx(i)+( (x-x_1)/(x_2-x_1) )*(dataset2%fx(i+1)-dataset2%fx(i)) last_sample=i GOTO 1000 end if end do ! next sample of file 2 write(*,*)'Sample not found in file 2, x=',x write(*,*)'First x=',dataset2%x(last_sample) write(*,*)'Last x=',dataset2%x(n_samples2-1) run_status='ERROR: Sample not found in file 2' CALL write_program_status() ! STOP 1 GOTO 2000 1000 CONTINUE ! we now have fx_1 and fx_2 at the current x value ! error is the magnitude of the difference between the values error=abs(fx_1-fx_2) ! The contribution to the difference measure is (1/2)*f(x_i)*((x_i+1)-x(i-1))/(total range of x) ! i.e. an integration over x using a piecewise linear integration scheme local_compare_results_value=local_compare_results_value+ & error*( ((dataset1%x(sample+1))-(dataset1%x(sample-1)) )/2d0) & /( (dataset1%x(sample_max+1))-(dataset1%x(sample_min-1)) ) 2000 CONTINUE end do ! next sample in the integration over x ! STAGE 4. write the result to screen and file write(*,8000)'compare_results value:',local_compare_results_value write(*,*)'Enter the filename for the compare_results data' read(*,*)opfilename OPEN(unit=local_file_unit,file=opfilename) write(local_file_unit,8000)'Result comparison:',local_compare_results_value 8000 format(A,F14.8) ! deallocate the data CALL deallocate_compare_results_data(dataset1) CALL deallocate_compare_results_data(dataset2) run_status='Finished_Correctly' CALL write_program_status() END PROGRAM compare_results