#!/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()