#!/bin/bash # # This is a script to generate a spice cable model # then run a validation test problem to # check that it is working OK # # Copyright (C) 2015 Chris Smartt # # This program 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. See license.txt for more details. # # This program 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. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . source gnuplot_functions # get the path to the TEST_CASE directory- note a special method is used in cygwin... if [ "$OSTYPE" == "cygwin" ]; then TEST_CASE_DIRECTORY=$( cygpath -m $(pwd) ) else TEST_CASE_DIRECTORY=$( pwd ) fi PROJECT_DIRECTORY2=$( dirname ${TEST_CASE_DIRECTORY} ) PROJECT_DIRECTORY=$( dirname ${PROJECT_DIRECTORY2} ) LIBRARY_OF_MODELS_TOP_LEVEL="${TEST_CASE_DIRECTORY}/MOD" LIBRARY_OF_CABLE_MODELS="${LIBRARY_OF_MODELS_TOP_LEVEL}/CABLE_MODELS" LIBRARY_OF_BUNDLE_MODELS="${LIBRARY_OF_MODELS_TOP_LEVEL}/BUNDLE_MODELS" LIBRARY_OF_SPICE_MODELS="${LIBRARY_OF_MODELS_TOP_LEVEL}/SPICE_MODELS" # the following keeps the circuit symbols in the local directory SYMBOL_DIR="./" # the following puts circuit symbols in the gschem directory #SYMBOL_DIR="/usr/share/gEDA/sym/local" EXECUTABLE_DIR="${PROJECT_DIRECTORY}/bin" NGSPICE_SUFFIX="_Ngspice.cir" # NOTE: you may need to change ownership of SYMBOL_DIR with something like the following command: # sudo chown chris:chris /usr/share/gEDA/sym/local FULL_TEST_CASE_LIST="FD_TWINAX2_OVER_GROUND_FASTHENRY FD_TWINAX2_OVER_GROUND_LAPLACE " ERROR_STRING="\ Run using the following command: generate_spice_cable_bundle_model action action is the process to perform: action=run NAME : Generate cable models, bundle model and Spice bundle model and validation spice model as required for the test case NAME. Run ngspice on the validation model and compare the spice result against the analytic solution action=plot NAME : Plot the results of the spice validation model and analytic solution to x11 terminal action=plot_wxt NAME : Plot the results of the spice validation model and analytic solution to wxt terminal action=plot_jpg NAME : Plot the results of the spice validation model and analytic solution to .jpg file action=plot_ref NAME : Plot the spice validation model results against reference results to x11 terminal action=plot_ref_wxt NAME : Plot the spice validation model results against reference results to wxt terminal action=plot_ref_jpg NAME : Plot the spice validation model results against reference results to jpg file action=plot_bundle NAME : Plot the bundle cross section to x11 terminal action=plot_bundle_wxt NAME : Plot the bundle cross section to wxt terminal action=plot_bundle_jpg NAME : Plot the bundle cross section to jpg file action=plot_bundle_png NAME : Plot the bundle cross section to png file action=plot_bundle_svg NAME : Plot the bundle cross section to svg file action=reference NAME : Update the reference results and the difference between the spice model and validation model with the current set of results action=check_error NAME : Quick check that the difference between the spice model and validation model is the same as for the reference data set action=clean NAME : Remove all files except those required to set up the problem and the reference results. action=clean_all NAME : Remove all files including the reference results. action=clean_mod NAME : Remove all files in the specified MOD directories. NAME can be one of the existing test cases or left blank to run all the test cases in the FULL_TEST_CASE_LIST defined in this script " if [ "$#" = "0" ] ; then # there is no action specified so write the error string to the screen and exit echo "$ERROR_STRING" elif [ "$#" = "1" ] ; then # no test case is specified so use the full test case list TEST_CASE_LIST=$FULL_TEST_CASE_LIST else # the second argument gives the test case to be run TEST_CASE_LIST=$2 fi ACTION=$1 if [ "$ACTION" = "clean_mod" ]; then pushd . cd $LIBRARY_OF_CABLE_MODELS rm -f *.cable popd pushd . cd $LIBRARY_OF_BUNDLE_MODELS rm -f *.bundle popd pushd . cd $LIBRARY_OF_SPICE_MODELS rm -f *.lib popd pushd . cd $SYMBOL_DIR rm -f *.asy *.sym popd exit fi # set up a new status file with the run command and action as a header echo "generate_spice_cable_bundle_model $ACTION " > status ERROR=" " # Loop over the specified test cases for TEST_CASE in $TEST_CASE_LIST do # Check that the test case directory exists if [ ! -d "$TEST_CASE" ]; then echo "${TEST_CASE} *** FAILED ***: does not exist" >> status continue fi echo "Running test case: ${TEST_CASE}" if [ "$ACTION" = "run" ] ; then ERROR=' ' # Run the test case(s) specified... cd $TEST_CASE if [ ! -d RUN_DIRECTORY ]; then # if the RUN_DIRECTORY doesn't exist then make it mkdir RUN_DIRECTORY else # if the RUN_DIRECTORY exists then empty the directory to run the test in echo "arg 3: $3" if [ "$3" != "spice_only" ]; then rm -f RUN_DIRECTORY/* echo " Cleaning RUN_DIRECTORY" fi fi # create a sed command which will substitute the local MOD directory for the test cases echo "{ s/LIBRARY_OF_CABLE_MODELS/${LIBRARY_OF_CABLE_MODELS//\//\\/}/g s/LIBRARY_OF_BUNDLE_MODELS/${LIBRARY_OF_BUNDLE_MODELS//\//\\/}/g s/LIBRARY_OF_SPICE_MODELS/${LIBRARY_OF_SPICE_MODELS//\//\\/}/g s/SYMBOL_DIR/${SYMBOL_DIR//\//\\/}/g }" > sed_command # Check that the appropriate files required to specify the inputs to the processes # are present for a viable run and copy the files into the RUN_DIRECTORY CABLE_FILE_LIST=$(ls *.cable_spec ) for CABLE_FILE in $CABLE_FILE_LIST do # run sed to copy to a new file with the library paths set appropriately sed -f sed_command $CABLE_FILE > RUN_DIRECTORY/$CABLE_FILE done NUMBER_OF_BUNDLE_SPEC_FILES=$(ls *.bundle_spec 2> /dev/null | wc -l) echo "NUMBER_OF_BUNDLE_SPEC_FILES $NUMBER_OF_BUNDLE_SPEC_FILES" if [ "$NUMBER_OF_BUNDLE_SPEC_FILES" -gt "1" ]; then cd .. echo "${TEST_CASE} *** FAILED ***: no more than one .bundle_spec file is expected" >> status continue elif [ "$NUMBER_OF_BUNDLE_SPEC_FILES" == "1" ]; then FILENAME=$(ls *.bundle_spec) sed -f sed_command $FILENAME > RUN_DIRECTORY/$FILENAME fi NUMBER_OF_SPICE_MODEL_SPEC_FILES=$(ls *.spice_model_spec 2> /dev/null | wc -l) echo "NUMBER_OF_SPICE_MODEL_SPEC_FILES $NUMBER_OF_SPICE_MODEL_SPEC_FILES" if [ "$NUMBER_OF_SPICE_MODEL_SPEC_FILES" -gt "1" ]; then cd .. echo "${TEST_CASE} *** FAILED ***: no more than one .spice_model_spec file is expected" >> status continue elif [ "$NUMBER_OF_SPICE_MODEL_SPEC_FILES" == "1" ]; then FILENAME=$(ls *.spice_model_spec) # copy the spice_model_spec file and set the correct SYMBOL_DIR sed -f sed_command ${FILENAME} > RUN_DIRECTORY/${FILENAME} fi # Go into the run directory to run the test case cd RUN_DIRECTORY if [ "$3" != "spice_only" ]; then # STAGE 1. GENERATE THE CABLE MODEL(S) # STAGE 1.1: look for any files with the extension .cable_spec echo " " CABLE_FILE_LIST=$(ls *.cable_spec 2> /dev/null) # STAGE 1.2:loop through these files runninng cable_model_builder for each of them CABLE_MODEL_BUILDER_STATUS="OK" for CABLE_FILE in $CABLE_FILE_LIST do CABLE_NAME=$(basename $CABLE_FILE .cable_spec) ${EXECUTABLE_DIR}/cable_model_builder ${CABLE_NAME} # Check that the process finished correctly read CHECK < run_status if [ "$CHECK" != "cable_model_builder:Finished_Correctly" ]; then # We need to organise the logic here such that the test case fails and # the system goes on to the next test case, not the next CABLE_FILE... echo "${TEST_CASE} *** FAILED ***: cable_model_builder $CABLE_FILE" >> ../../status CABLE_MODEL_BUILDER_STATUS="failed" continue fi done # exit the test case if the cable model builder failed if [ "$CABLE_MODEL_BUILDER_STATUS" = "failed" ]; then cd ../.. continue fi # STAGE 2. GENERATE THE BUNDLE MODEL echo " " # STAGE 2.1: count files with the extension .bundle_spec and return with an error if the result is not 0 or 1 if [ "$NUMBER_OF_BUNDLE_SPEC_FILES" == "1" ]; then FILENAME=$(ls *.bundle_spec) CABLE_BUNDLE_NAME=$(basename $FILENAME .bundle_spec) ${EXECUTABLE_DIR}/cable_bundle_model_builder ${CABLE_BUNDLE_NAME} # Check that the process finished correctly read CHECK < run_status if [ "$CHECK" != "cable_bundle_model_builder:Finished_Correctly" ]; then cd ../.. echo "${TEST_CASE} *** FAILED ***: cable_bundle_model_builder" >> status continue fi fi #spice_only fi # STAGE 3.GENERATE THE SPICE CABLE MODEL echo " " # STAGE 3.1: Count files with the extension .spice_model_spec and return with an error if the result is not 1 if [ "$NUMBER_OF_SPICE_MODEL_SPEC_FILES" == "1" ]; then # STAGE 3.2:run the spice cable bundle model builder FILENAME=$(ls *.spice_model_spec) SPICE_CABLE_BUNDLE_NAME=$(basename $FILENAME .spice_model_spec) ${EXECUTABLE_DIR}/spice_cable_bundle_model_builder ${SPICE_CABLE_BUNDLE_NAME} # Check that the process finished correctly read CHECK < run_status if [ "$CHECK" != "spice_cable_bundle_model_builder:Finished_Correctly" ]; then cd ../.. echo "${TEST_CASE} *** FAILED ***: spice_cable_bundle_model_builder" >> status continue fi # STAGE 4.RUN NGSPICE # STAGE 4.1: COUNT FILES WITH THE EXTENSION .CIR AND RETURN WITH AN ERROR IF THE RESULT IS NOT 1 if [ $(ls *${NGSPICE_SUFFIX} | wc -l) != "1" ]; then cd ../.. echo "${TEST_CASE} ERROR: a single .cir file is expected" continue fi SPICE_INPUT_FILE=$(ls *${NGSPICE_SUFFIX}) SPICE_PROBLEM_NAME=$( basename $SPICE_INPUT_FILE .cir ) SPICE_OUTPUT_NAME="spice_solution.dat" echo " " echo "ngspice:Started" ngspice -b $SPICE_INPUT_FILE -o $SPICE_OUTPUT_NAME # check that the process finished correctly NGPSICE_STATUS=$? if [[ $NGPSICE_STATUS != 0 ]]; then cd ../.. echo "${TEST_CASE} *** FAILED ***: ngspice, error code:$NGPSICE_STATUS" >> status continue else echo "${TEST_CASE} ngspice:Finished_correctly" fi # Stage 5: COMPARE THE RUN_DIRECTORY OF THE SPICE MODEL AGAINST THE ANALYTIC MODEL USING THE COMPARE_RUN_DIRECTORY PROCESS # create an input file for the result comparison process echo "analytic_solution.dat 1 2 $SPICE_OUTPUT_NAME 2 3 result_comparison.dat " > compare_results_in.txt echo " " ${EXECUTABLE_DIR}/compare_results < compare_results_in.txt read CHECK < run_status if [ "$CHECK" != "compare_results:Finished_Correctly" ]; then cd ../.. echo "${TEST_CASE} *** FAILED ***: compare_results" >> status continue fi # add the error between spice and analytic solutions to the status line read ERROR < result_comparison.dat # Create a file 'finished_correctly' to indicate that the run has finished_correctly touch finished_correctly # .spice_model_spec file exists fi cd ../.. # finished "$ACTION" = "run" elif [ "$ACTION" = "plot_bundle" ]; then cd ${TEST_CASE}/RUN_DIRECTORY TERMINAL=x11 write_gnuplot_plot_bundle cd ../.. elif [ "$ACTION" = "plot_bundle_jpg" ]; then cd ${TEST_CASE}/RUN_DIRECTORY TERMINAL=jpeg OUTPUT_FILE=${TEST_CASE}_bundle_cross_section.jpg write_gnuplot_plot_bundle cd ../.. elif [ "$ACTION" = "plot_bundle_wxt" ]; then cd ${TEST_CASE}/RUN_DIRECTORY TERMINAL=wxt write_gnuplot_plot_bundle cd ../.. elif [ "$ACTION" = "plot_bundle_png" ]; then cd ${TEST_CASE}/RUN_DIRECTORY TERMINAL=png OUTPUT_FILE=${TEST_CASE}_bundle_cross_section.png write_gnuplot_plot_bundle cd ../.. elif [ "$ACTION" = "plot_bundle_svg" ]; then cd ${TEST_CASE}/RUN_DIRECTORY TERMINAL=svg OUTPUT_FILE=${TEST_CASE}_bundle_cross_section.svg write_gnuplot_plot_bundle cd ../.. elif [ "$ACTION" = "clean" ]; then cd $TEST_CASE # Empty the directory to run the test in rm -f RUN_DIRECTORY/* rm -f sed_command cd .. elif [ "$ACTION" = "clean_all" ]; then cd $TEST_CASE # Empty the directory to run the test in rm -f RUN_DIRECTORY/* rm -f sed_command cd .. else # All other actions assume that the test case has been run so check that this is the case if [ ! -d ${TEST_CASE}/RUN_DIRECTORY ]; then # if the RUN_DIRECTORY doesn't exist then the problem can't have been run echo "${TEST_CASE} *** FAILED ***: The RUN_DIRECTORY is missing" >> status continue fi if [ ! -f ${TEST_CASE}/RUN_DIRECTORY/finished_correctly ]; then # if the RUN_DIRECTORY/finished_correctly file doesn't exist then # the run cannot have proceeded as far as producing spice simulation results echo "${TEST_CASE}: *** No simulation results are available for action: $ACTION " >> status continue fi # no other checks SHOULD be necessary now... # read the analytic solution file header to work out the type of simulation which has been run read HEADER < ${TEST_CASE}/RUN_DIRECTORY/analytic_solution.dat if [ "$HEADER" = "#LOG_FREQUENCY_DATA" ]; then # Set the gnuplot parameters for a Log frequency plot XLABEL=Frequency\(Hz\) YLABEL=V\(f\) XSCALE=logscale elif [ "$HEADER" = "#LIN_FREQUENCY_DATA" ]; then # Set the gnuplot parameters for a Linear frequency plot XLABEL=Frequency\(Hz\) YLABEL=V\(f\) XSCALE=nologscale elif [ "$HEADER" = "#TIME_DOMAIN_DATA" ]; then # Set the gnuplot parameters for a Time domain plot XLABEL=Time\(s\) YLABEL=V\(t\) XSCALE=nologscale else echo "$TEST_CASE Error reading analytic solution file header :$HEADER" >> status continue # HEADER type fi TITLE=$TEST_CASE OUTPUT_FILE="" if [ "$ACTION" = "plot" ]; then cd ${TEST_CASE}/RUN_DIRECTORY TERMINAL=x11 write_gnuplot_result cd ../.. elif [ "$ACTION" = "plot_wxt" ]; then cd ${TEST_CASE}/RUN_DIRECTORY TERMINAL=wxt write_gnuplot_result cd ../.. elif [ "$ACTION" = "plot_jpg" ]; then cd ${TEST_CASE}/RUN_DIRECTORY TERMINAL=jpeg OUTPUT_FILE=${TEST_CASE}_result.jpg write_gnuplot_result cd ../.. elif [ "$ACTION" = "plot_ref" ]; then cd ${TEST_CASE}/RUN_DIRECTORY TERMINAL=x11 write_gnuplot_reference_result cd ../.. elif [ "$ACTION" = "plot_ref_jpg" ]; then cd ${TEST_CASE}/RUN_DIRECTORY TERMINAL=jpeg OUTPUT_FILE=${TEST_CASE}_reference_result.jpg write_gnuplot_reference_result cd ../.. elif [ "$ACTION" = "plot_ref_wxt" ]; then cd ${TEST_CASE}/RUN_DIRECTORY TERMINAL=wxt write_gnuplot_reference_result cd ../.. elif [ "$ACTION" = "reference" ]; then cd $TEST_CASE cp RUN_DIRECTORY/result_comparison.dat result_comparison.dat_reference cp RUN_DIRECTORY/spice_solution.dat spice_solution.dat_reference cp RUN_DIRECTORY/analytic_solution.dat analytic_solution.dat_reference cd .. elif [ "$ACTION" = "check_error" ]; then cd $TEST_CASE cat RUN_DIRECTORY/result_comparison.dat # Check whether there is an existing reference comparison file and if so check the difference if [ -f result_comparison.dat_reference ]; then cmp result_comparison.dat_reference RUN_DIRECTORY/result_comparison.dat RETURN_CODE=$? if [[ $RETURN_CODE == 0 ]] then cd .. echo "Checking the current results against reference results: OK " echo "${TEST_CASE} FINISHED_CORRECTLY: error = reference error" >> status continue else OLD_VALUE=$(cat result_comparison.dat_reference) NEW_VALUE=$(cat RUN_DIRECTORY/result_comparison.dat) cd .. echo "Checking the current results against reference results: FAILED " echo "${TEST_CASE} *** FAILED ***: error != reference error" >> status echo "Old value: $OLD_VALUE" >> status echo "New value: $NEW_VALUE" >> status continue fi else cd .. echo "${TEST_CASE} *** FAILED ***: The result_comparison.dat_reference file is missing" >> status continue fi cd .. else echo " ERROR: unknown action, $ACTION" exit 1 # end of ACTION options for ACTION != (run clean or clean_all) fi # end of ACTION options fi echo " " echo "Test_case $TEST_CASE Finished correctly" echo " " echo "$TEST_CASE: Finished correctly $ERROR" >> status done if [ "$ACTION" = "clean_all" ] ; then # clean the library of cable models rm -rf $LIBRARY_OF_CABLE_MODELS/* echo "Directory for individual cable models" > $LIBRARY_OF_CABLE_MODELS/readme.md rm -rf $LIBRARY_OF_BUNDLE_MODELS/* echo "Directory for cable bundle models and directories with the associated Spice cable bundle models" > $LIBRARY_OF_BUNDLE_MODELS/readme.md rm -f status fi if [[ "$ACTION" != "clean" && "$ACTION" != "clean_all" ]] ; then echo "__________________________________" echo " " echo "Completed all specified test cases" echo "__________________________________" echo " " echo "STATUS:" echo " " cat status echo " " fi