Source code for utilities.brisFDTD_ID_info

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""
Converts between the numeric IDs **numID** (01, 02, 67, etc) and alphabetic IDs **alphaID** (01, A1, df, jk, {l, etc) used by Bristol FDTD for its data files.

.. note:: Since BFDTD 2008, "ba" comes after "az" instead of "a{".

  Make sure you specify "pre_2008_BFDTD_version = True" if you are working with data generated by BFDTD versions < 2008!!!
  
  Please stop using the old BFDTD 2003 for any new simulations.

.. note:: If there is a mix of time snapshots, epsilon snapshots and/or mode filtered probes, they will be numbered together!!!

  i.e. 1 esnap + 1 tsnap will lead to x1...+x2... according to their respective order of appearance in the .inp file.
  
.. note:: snap_time_number starts at 0 for ModeFilteredProbes and at 1 for time and epsilon snapshots.

Maximum amount of output files BFDTD can generate: 2549 time/epsilon snapshots for BFDTD 2014, but this might lead to bad filenames. (This might actually be a system-specific limit on the maximum number of simultaneously open files.)

.. todo:: Check the limits of the different numbering systems
.. todo:: Create class/structure to store the various info related to a .prn file? (numID, alphaID, etc)
.. todo:: Separate new filename creation from alphaID_to_numID function.
.. todo:: Add format specification option for new filename.

.. todo:: Replace test functions with proper python module test system.
"""

import sys
import math
import re
import os
import unittest

FREQUENCYSNAPSHOT_MAX_PRE_2008_VERSION = 836
FREQUENCYSNAPSHOT_MAX_POST_2008_VERSION = 806
FREQUENCYSNAPSHOT_MAX = FREQUENCYSNAPSHOT_MAX_POST_2008_VERSION
TIMESNAPSHOT_MAX = 439
MODEFILTEREDPROBE_MAX = 439
PROBE_MAX = 439
SAFE_MAX_ALL = 52
SAFE_MAX_POST_2008_VERSION = 99

#MODEFILTEREDPROBE_MAX = 43 # old max, probably related to BFDTD 2003...
#MODEFILTEREDPROBE_MAX = 118 # old max, probably related to BFDTD 2003...

[docs]def numID_to_alphaID_FrequencySnapshot(numID, snap_plane = 'x', probe_ident = '_id_', snap_time_number = 0, pre_2008_BFDTD_version = False): ''' Converts numeric IDs to alpha IDs used by Bristol FDTD for frequency snapshots. :param bool update_limits: If true, updateLimits() will be called. :param int numID: numeric ID :param str snap_plane: snapshot plane letter, i.e. 'x', 'y' or 'z'. Default: 'x' :param str probe_ident: ID string used in data output. Default: '_id_' :param int snap_time_number: "snapshot time number", i.e. the index at the end of data filenames. Default: 0 :param bool pre_2008_BFDTD_version: If True, the pre-2008 BFDTD indexing will be used. Default: False :return: (filename, alphaID, pair) Examples: * 26 -> z * 26 + 26 -> az * 26 + 27 -> ba for BFDTD version >= 2008 * 26 + 27 -> a{ for BFDTD version < 2008 Maximum values: * MAXIMUM NUMBER OF SNAPSHOTS: 32767 (=(2^8)*(2^8)/2 -1) * MAXIMUM NUMBER OF SNAPSHOTS BEFORE RETURN to aa: 6938 = 26+256*27 * MAXIMUM NUMBER OF SNAPSHOTS BEFORE DUPLICATE IDs: 4508 = 26+(6-(ord('a')-1)+256)*27+1 (6=character before non-printable bell character) * MAXIMUM NUMBER OF SNAPSHOTS BEFORE ENTERING DANGER AREA (non-printable characters): * 806 = 26 + (126-(ord('a')-1))*26 (first digit: a-~, second digit: a-z) for BFDTD version >= 2008 * 836 = 26 + (126-(ord('a')-1))*27 (first digit: a-~, second digit: a-{) for BFDTD version < 2008 ''' filename = None alphaID = None pair = None if pre_2008_BFDTD_version: FREQUENCYSNAPSHOT_MAX = FREQUENCYSNAPSHOT_MAX_PRE_2008_VERSION else: FREQUENCYSNAPSHOT_MAX = FREQUENCYSNAPSHOT_MAX_POST_2008_VERSION if numID<1 or numID>FREQUENCYSNAPSHOT_MAX: raise ValueError('ERROR: numID must be between 1 and '+str(FREQUENCYSNAPSHOT_MAX)+' or else you will suffer death by monkeys!!!') if snap_time_number<0 or snap_time_number>99: raise ValueError('ERROR: snap_time_number must be between 0 and 99 or else you will suffer death by monkeys!!! snap_time_number = {}'.format(snap_time_number)) #snap_time_number = mod(snap_time_number,100); ilo = snap_time_number%10 # gets the 10^0 digit from snap_time_number ihi = snap_time_number//10 # gets the 10^1 digit from snap_time_number if pre_2008_BFDTD_version: if numID < 27: alphaID = chr(numID + ord('a') - 1) else: alphaID = chr(numID//27 + ord('a')-1) + chr(numID%27 + ord('a')) else: if numID < 27: alphaID = chr(numID + ord('a') - 1) else: alphaID = chr((numID-1)//26 + ord('a') - 1) + chr((numID-1)%26 + ord('a')) filename = snap_plane + alphaID + probe_ident + chr(ihi + ord('0')) + chr(ilo + ord('0')) + '.prn' pair = str(numID) + ':' + alphaID return filename, alphaID, pair
[docs]def numID_to_alphaID_TimeSnapshot(numID, snap_plane = 'x', probe_ident = '_id_', snap_time_number = 1): ''' Converts numeric IDs to alpha IDs used by Bristol FDTD for time snapshots. .. note:: This function can also be used for epsilon snapshots, since they are just a subclass of time snapshots. .. todo:: Should the "snap_time_number" in the resulting filename be "snap_time_number+1"? Frequency snapshots indexing starts at 0, while time snapshot indexing starts at 1. So in order to keep things consistent, the python code should always start indexing at 0. :return: (filename, alphaID, pair) Examples: * 99 -> 99 * 100 -> :0 ''' filename = None alphaID = None pair = None if numID < 1 or numID > TIMESNAPSHOT_MAX: raise ValueError('ERROR: numID = {}. numID must be between 1 and {} or else you will suffer death by monkeys!!!'.format(numID, TIMESNAPSHOT_MAX)) if snap_time_number < 0 or snap_time_number > 99: raise ValueError('ERROR: snap_time_number = {}. snap_time_number must be between 0 and 99 or else you will suffer death by monkeys!!!'.format(snap_time_number)) ilo = snap_time_number%10 ihi = snap_time_number//10 if numID<10: alphaID = chr(numID + ord('0')) else: alphaID = chr((numID//10) + ord('0')) + chr((numID%10) + ord('0')) filename = snap_plane + alphaID + probe_ident + chr(ihi + ord('0')) + chr(ilo + ord('0')) + '.prn' pair = str(numID) + ':' + alphaID return (filename, alphaID, pair)
[docs]def numID_to_alphaID_Probe(numID, probe_ident = '_id_'): ''' Converts numeric IDs to alpha IDs used by Bristol FDTD for probes. :return: (filename, alphaID, pair) Examples: * 99 -> 99 * 100 -> :0 ''' if numID < 1 or numID > PROBE_MAX: raise ValueError('ERROR: numID must be between 1 and {} or else you will suffer death by monkeys!!!'.format(PROBE_MAX)) ilo = numID%10 ihi = numID//10 alphaID = chr(ihi + ord('0')) + chr(ilo + ord('0')) filename = 'p' + alphaID + probe_ident + '.prn' pair = str(numID) + ':' + alphaID return filename, alphaID, pair
[docs]def numID_to_alphaID_ModeFilteredProbe(numID, probe_ident = '_id_', snap_time_number = 1): ''' Converts numeric IDs to alpha IDs used by Bristol FDTD for mode filtered probes. :return: (filename, alphaID, pair) Examples: * 9 -> 9 * 10 -> : ''' if numID<1 or numID>MODEFILTEREDPROBE_MAX: raise ValueError('ERROR: numID must be between 1 and {} or else you will suffer death by monkeys!!!'.format(MODEFILTEREDPROBE_MAX)) (filename, alphaID, pair) = numID_to_alphaID_TimeSnapshot(numID, snap_plane = 'i', probe_ident = probe_ident, snap_time_number = snap_time_number) #alphaID = chr(numID + ord('0')); #filename = 'i' + alphaID + probe_ident + '00.prn'; #pair = str(numID) + ':' + alphaID return (filename, alphaID, pair)
[docs]def alphaID_to_numID(alphaID_or_filename, expected_object_type=None, probe_ident=None, pre_2008_BFDTD_version=False): ''' Converts alpha IDs used by Bristol FDTD to numeric IDs. :return: (numID, snap_plane, probe_ident, snap_time_number, fixed_filename, object_type) Examples: * z -> 26 * a{ -> 26+27 * 99 -> 99 * :0 -> 100 ''' # default values numID = None snap_plane = None snap_time_number = None alphaID = None object_type = None fixed_filename = None if not isinstance(alphaID_or_filename, str): raise ValueError('ERROR: alphaID_or_filename should be a string.') (directory,basename) = os.path.split(alphaID_or_filename) if probe_ident is None: pattern_probe_ident = r"(.*)" else: pattern_probe_ident = r"(" + probe_ident + r")" if pre_2008_BFDTD_version: pattern_fsnap = r"([a-z\{\|\}~][a-z\{]|[a-z])" else: pattern_fsnap = r"([a-z\{\|\}~][a-z]|[a-z])" pattern_alphaID_fsnap = re.compile(r"^" + pattern_fsnap + r"$") pattern_filename_fsnap = re.compile(r"^([xyz])" + pattern_fsnap + pattern_probe_ident + r"(\d\d)\.prn$") m_alphaID_fsnap = pattern_alphaID_fsnap.match(basename) m_filename_fsnap = pattern_filename_fsnap.match(basename) pattern_tsnap = r"([1-9A-Z:;<=>?@[]\d|\d)" pattern_alphaID_tsnap = re.compile(r"^" + pattern_tsnap + r"$") pattern_filename_tsnap = re.compile(r"^([xyz])" + pattern_tsnap + pattern_probe_ident + r"(\d\d)\.prn$") m_alphaID_tsnap = pattern_alphaID_tsnap.match(basename) m_filename_tsnap = pattern_filename_tsnap.match(basename) pattern_probe = r"([0-9A-Z:;<=>?@[]\d)" pattern_alphaID_probe = re.compile(r"^" + pattern_probe + r"$") pattern_filename_probe = re.compile(r"^p" + pattern_probe + pattern_probe_ident + r"\.prn$") m_alphaID_probe = pattern_alphaID_probe.match(basename) m_filename_probe = pattern_filename_probe.match(basename) # .. todo:: Pattern could probably be improved... pattern_mfprobe = r"([0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0¡¢£¤¥¦]\d|\d)" pattern_alphaID_mfprobe = re.compile(r"^" + pattern_mfprobe + r"$") pattern_filename_mfprobe = re.compile(r"^i" + pattern_mfprobe + pattern_probe_ident + r"(\d\d)\.prn$") m_alphaID_mfprobe = pattern_alphaID_mfprobe.match(basename) m_filename_mfprobe = pattern_filename_mfprobe.match(basename) if m_alphaID_fsnap and (expected_object_type is None or expected_object_type=='fsnap'): alphaID = m_alphaID_fsnap.group(1) object_type = 'fsnap' elif m_alphaID_tsnap: alphaID = m_alphaID_tsnap.group(1) object_type = 'probe or tsnap or esnap or mfprobe' elif m_alphaID_probe: alphaID = m_alphaID_probe.group(1) object_type = 'probe or tsnap or esnap or mfprobe' elif m_alphaID_mfprobe: alphaID = m_alphaID_mfprobe.group(1) object_type = 'probe or tsnap or esnap or mfprobe' elif m_filename_fsnap: snap_plane = m_filename_fsnap.group(1) alphaID = m_filename_fsnap.group(2) probe_ident = m_filename_fsnap.group(3) snap_time_number = int(m_filename_fsnap.group(4)) object_type = 'fsnap' elif m_filename_tsnap: # TODO: look into .prn file to determine if it is a tsnap or esnap? snap_plane = m_filename_tsnap.group(1) alphaID = m_filename_tsnap.group(2) probe_ident = m_filename_tsnap.group(3) snap_time_number = int(m_filename_tsnap.group(4)) object_type = 'tsnap' elif m_filename_probe: alphaID = m_filename_probe.group(1) probe_ident = m_filename_probe.group(2) object_type = 'probe' elif m_filename_mfprobe: alphaID = m_filename_mfprobe.group(1) probe_ident = m_filename_mfprobe.group(2) snap_time_number = int(m_filename_mfprobe.group(3)) object_type = 'mfprobe' else: sys.stderr.write('ERROR: All matches failed : basename = {}\n'.format(basename)) if alphaID: if object_type == 'fsnap': if len(alphaID) == 1: numID = ord(alphaID) - ord('a') + 1 elif len(alphaID) == 2: if pre_2008_BFDTD_version: numID = 27*(ord(alphaID[0]) - ord('a') + 1) + (ord(alphaID[1]) - ord('a')) else: numID = 26*(ord(alphaID[0]) - ord('a') + 1) + (ord(alphaID[1]) - ord('a') + 1) else: sys.stderr.write('ERROR: alphaID is not of length 1 or 2: alphaID = {}\n'.format(alphaID)) if not (snap_plane is None or numID is None or probe_ident is None or snap_time_number is None): fixed_filename = os.path.join(directory, 'fsnap_' + snap_plane + "%03d"%numID + probe_ident + "%02d"%snap_time_number + '.prn') elif object_type == 'tsnap': if len(alphaID) == 1: numID = ord(alphaID[0])-ord('0') else: numID = 10*(ord(alphaID[0])-ord('0')) + (ord(alphaID[1])-ord('0')) if not (snap_plane is None or numID is None or probe_ident is None or snap_time_number is None): fixed_filename = os.path.join(directory, 'tsnap_' + snap_plane + "%03d"%numID + probe_ident + "%02d"%snap_time_number + '.prn') elif object_type == 'probe': numID = 10*(ord(alphaID[0])-ord('0')) + (ord(alphaID[1])-ord('0')) if not (numID is None or probe_ident is None): fixed_filename = os.path.join(directory, 'p' + "%03d"%numID + probe_ident + '.prn') elif object_type == 'mfprobe': if len(alphaID) == 1: numID = ord(alphaID[0])-ord('0') else: numID = 10*(ord(alphaID[0])-ord('0')) + (ord(alphaID[1])-ord('0')) if not (numID is None or probe_ident is None): fixed_filename = os.path.join(directory, 'mfprobe_i' + "%03d"%numID + probe_ident + '00.prn') elif object_type == 'probe or tsnap or esnap or mfprobe': if len(alphaID) == 1: numID = ord(alphaID[0])-ord('0') else: numID = 10*(ord(alphaID[0])-ord('0')) + (ord(alphaID[1])-ord('0')) else: sys.stderr.write('ERROR: Unknown object type for basename = {} and alphaID = {}\n'.format(basename, alphaID)) else: sys.stderr.write('ERROR: alphaID not found for basename = {}\n'.format(basename)) return (numID, snap_plane, probe_ident, snap_time_number, fixed_filename, object_type)
[docs]class Test_brisFDTD_ID_info_Functions(unittest.TestCase):
[docs] def FrequencySnapshotID_ViceVersa(self, pre_2008_BFDTD_version): if pre_2008_BFDTD_version: FREQUENCYSNAPSHOT_MAX = FREQUENCYSNAPSHOT_MAX_PRE_2008_VERSION else: FREQUENCYSNAPSHOT_MAX = FREQUENCYSNAPSHOT_MAX_POST_2008_VERSION N = FREQUENCYSNAPSHOT_MAX for i in range(N): numID_in = i+1 print('==> numID_in = {}'.format(numID_in)) print('numID_to_alphaID_FrequencySnapshot(numID_in) check') filename_in, alphaID, pair = numID_to_alphaID_FrequencySnapshot(numID_in, pre_2008_BFDTD_version=pre_2008_BFDTD_version) print((filename_in, alphaID, pair)) print('alphaID_to_numID(alphaID) check') numID_out, snap_plane, probe_ident, snap_time_number, fixed_filename, object_type = alphaID_to_numID(alphaID, pre_2008_BFDTD_version=pre_2008_BFDTD_version) print((numID_out, snap_plane, probe_ident, snap_time_number, fixed_filename, object_type)) if numID_out != numID_in: raise print('alphaID_to_numID(filename_in) check') numID_out, snap_plane, probe_ident, snap_time_number, fixed_filename, object_type = alphaID_to_numID(filename_in, pre_2008_BFDTD_version=pre_2008_BFDTD_version) print((numID_out, snap_plane, probe_ident, snap_time_number, fixed_filename, object_type)) if numID_out != numID_in: raise return
[docs] def FrequencySnapshotID_List(self, pre_2008_BFDTD_version): if pre_2008_BFDTD_version: FREQUENCYSNAPSHOT_MAX = FREQUENCYSNAPSHOT_MAX_PRE_2008_VERSION else: FREQUENCYSNAPSHOT_MAX = FREQUENCYSNAPSHOT_MAX_POST_2008_VERSION N = FREQUENCYSNAPSHOT_MAX for i in range(N): numID_in = i+1 filename_in, alphaID, pair = numID_to_alphaID_FrequencySnapshot(numID_in, pre_2008_BFDTD_version=pre_2008_BFDTD_version) print(pair) return
[docs] def test_FrequencySnapshotID_ViceVersa_pre_2008_BFDTD_version(self): self.FrequencySnapshotID_ViceVersa(True) return
[docs] def test_FrequencySnapshotID_ViceVersa_post_2008_BFDTD_version(self): self.FrequencySnapshotID_ViceVersa(False) return
[docs] def test_FrequencySnapshotID_List_pre_2008_BFDTD_version(self): self.FrequencySnapshotID_List(True) return
[docs] def test_FrequencySnapshotID_List_post_2008_BFDTD_version(self): self.FrequencySnapshotID_List(False) return
[docs] def test_TimeSnapshotID_ViceVersa(self): N = TIMESNAPSHOT_MAX for i in range(N): numID_in = i+1 print('numID_to_alphaID_TimeSnapshot(numID_in) check') filename_in, alphaID, pair = numID_to_alphaID_TimeSnapshot(numID_in) print((filename_in, alphaID, pair)) print('alphaID_to_numID(alphaID) check') numID_out, snap_plane, probe_ident, snap_time_number, fixed_filename, object_type = alphaID_to_numID(alphaID) print((numID_out, snap_plane, probe_ident, snap_time_number, fixed_filename, object_type)) if numID_out != numID_in: raise print('alphaID_to_numID(filename_in) check') numID_out, snap_plane, probe_ident, snap_time_number, fixed_filename, object_type = alphaID_to_numID(filename_in) print((numID_out, snap_plane, probe_ident, snap_time_number, fixed_filename, object_type)) if numID_out != numID_in: raise return
[docs] def test_ProbeID_ViceVersa(self): N = PROBE_MAX for i in range(N): numID_in = i+1 print('numID_to_alphaID_Probe(numID_in) check') filename_in, alphaID, pair = numID_to_alphaID_Probe(numID_in) print((filename_in, alphaID, pair)) print('alphaID_to_numID(alphaID) check') numID_out, snap_plane, probe_ident, snap_time_number, fixed_filename, object_type = alphaID_to_numID(alphaID) print((numID_out, snap_plane, probe_ident, snap_time_number, fixed_filename, object_type)) if numID_out != numID_in: raise print('alphaID_to_numID(filename_in) check') numID_out, snap_plane, probe_ident, snap_time_number, fixed_filename, object_type = alphaID_to_numID(filename_in) print((numID_out, snap_plane, probe_ident, snap_time_number, fixed_filename, object_type)) if numID_out != numID_in: raise return
[docs] def test_ModeFilteredProbeID_ViceVersa(self): #print('CACCACACACACACA') #raise Exception('CACACCACCCCCCC') N = MODEFILTEREDPROBE_MAX for i in range(N): numID_in = i+1 print('--> numID_in = {}'.format(numID_in)) #raise print('numID_to_alphaID_ModeFilteredProbe(numID_in) check') filename_in, alphaID, pair = numID_to_alphaID_ModeFilteredProbe(numID_in) print((filename_in, alphaID, pair)) print('alphaID_to_numID(alphaID) check') numID_out, snap_plane, ModeFilteredProbe_ident, snap_time_number, fixed_filename, object_type = alphaID_to_numID(alphaID,'mfprobe') print((numID_out, snap_plane, ModeFilteredProbe_ident, snap_time_number, fixed_filename, object_type)) if numID_out != numID_in: raise print('alphaID_to_numID(filename_in) check') numID_out, snap_plane, ModeFilteredProbe_ident, snap_time_number, fixed_filename, object_type = alphaID_to_numID(filename_in) print((numID_out, snap_plane, ModeFilteredProbe_ident, snap_time_number, fixed_filename, object_type)) if numID_out != numID_in: raise Exception('numID_out={} numID_in={} filename_in={}'.format(numID_out, numID_in, filename_in)) return
[docs] def test_TimeSnapshotID_List(self): N = TIMESNAPSHOT_MAX for i in range(N): numID_in = i+1 filename_in, alphaID, pair = numID_to_alphaID_TimeSnapshot(numID_in) print(pair) return
[docs] def test_ProbeID_List(self): N = PROBE_MAX for i in range(N): numID_in = i+1 filename_in, alphaID, pair = numID_to_alphaID_Probe(numID_in) print(pair) return
[docs] def test_ModeFilteredProbeID_List(self): N = MODEFILTEREDPROBE_MAX for i in range(N): numID_in = i+1 filename_in, alphaID, pair = numID_to_alphaID_ModeFilteredProbe(numID_in) print(pair) return
if __name__ == "__main__": unittest.main()