3
0
mirror of https://github.com/triqs/dft_tools synced 2024-06-02 11:25:29 +02:00

* Completed group parser

* Added a consistency check for groups and shells
 * Added scenario descriptions to the test suite
This commit is contained in:
Oleg Peil 2015-02-15 16:42:48 +01:00 committed by Michel Ferrero
parent 0d1ef0ac97
commit 9ab6116b28
2 changed files with 149 additions and 20 deletions

View File

@ -241,10 +241,12 @@ class ConfigParameters:
issue_warning("Shell indices are not uniform or not starting from 1. "
"This might be an indication of a incorrect setup.")
# Parse shell parameters
self.shells = {}
# Parse shell parameters and put them into a list sorted according to the original indices
self.shells = []
for ind in sh_inds:
self.shells[ind] = {}
shell = {}
# Store the original user-defined index
shell['user_index'] = ind
section = self.sh_sections[ind]
# Shell required parameters
@ -252,14 +254,14 @@ class ConfigParameters:
print
print " Required shell parameters:"
parsed = self.parse_parameter_set(section, self.sh_required, exception=True)
self.shells[ind].update(parsed)
shell.update(parsed)
# Shell optional parameters
if self.verbosity > 0:
print
print " Optional shell parameters:"
parsed = self.parse_parameter_set(section, self.sh_optional, exception=False)
self.shells[ind].update(parsed)
shell.update(parsed)
# Group required parameters
# Must be given if no group is explicitly specified
@ -268,14 +270,16 @@ class ConfigParameters:
print
print " Required group parameters:"
parsed = self.parse_parameter_set(section, self.gr_required, exception=False)
self.shells[ind].update(parsed)
shell.update(parsed)
# Group optional parameters
if self.verbosity > 0:
print
print " Optional group parameters:"
parsed = self.parse_parameter_set(section, self.gr_optional, exception=False)
self.shells[ind].update(parsed)
shell.update(parsed)
self.shells.append(shell)
################################################################################
#
@ -294,20 +298,66 @@ class ConfigParameters:
self.ngroups = len(sec_groups)
self.groups = []
# Parse group parameters
for section in sec_groups:
group = {}
# Extract group index (FIXME: do we really need it?)
gr_patt2 = re.compile('group +([0-9]*)$', re.IGNORECASE)
try:
gr_ind = int(gr_patt2.match(section).groups()[0])
except (ValueError, AttributeError):
raise ValueError("Failed to extract group index from a group name: %s"%(section))
group['index'] = gr_ind
# Group required parameters
if self.verbosity > 0:
print
print " Required group parameters:"
parsed = self.parse_parameter_set(section, self.gr_required, exception=True)
group.update(parsed)
# Group optional parameters
if self.verbosity > 0:
print
print " Optional group parameters:"
parsed = self.parse_parameter_set(section, self.gr_optional, exception=False)
group.update(parsed)
self.groups.append(group)
# Sort groups according to indices defined in the config-file
if self.ngroups > 0:
self.groups.sort(key=lambda g: g['index'])
################################################################################
#
# groups_shells_consistency()
#
################################################################################
def groups_shells_consistency(self):
"""
Ensures consistency between groups and shells.
In particular:
- if no groups are explicitly defined and only shell is defined create
a group automatically
- check the existance of all shells referenced in the groups
- check that all shells are referenced in the groups
"""
# Special case: no groups is defined
if self.ngroups == 0:
# Check that 'nshells = 1'
assert self.nshells == 1, "At least one group must be defined if there are more than one shells."
# Otherwise create a single group taking group information from [Shell] section
self.groups = [{}]
self.groups.append({})
# Check that the single '[Shell]' section contains enough information
# and move it to the `groups` dictionary
ind = self.sh_sections.keys()[0]
try:
for par in self.gr_required.keys():
key = self.gr_required[par][0]
value = self.shells[ind].pop(key)
value = self.shells[0].pop(key)
self.groups[0][key] = value
except KeyError:
message = "One [Shell] section is specified but no explicit [Group] section is provided."
@ -316,16 +366,67 @@ class ConfigParameters:
raise KeyError(message)
# Do the same for optional group parameters, but do not raise an exception
for par in self.gr_required.keys():
for par in self.gr_optional.keys():
try:
key = self.gr_required[par][0]
key = self.gr_optional[par][0]
value = self.shells[ind].pop(key)
self.groups[0][key] = value
except KeyError:
continue
self.groups.update({'shells': [self.shells[ind]]})
# Add the index of the single shell into the group
self.groups.update({'shells': 0})
#
# Consistency checks
#
# Check the existance of shells referenced in the groups
def find_shell_by_user_index(uindex):
for ind, shell in enumerate(self.shells):
if shell['user_index'] == uindex:
return shell
raise KeyError
sh_inds = []
for group in self.groups:
gr_shells = group['shells']
for user_ind in gr_shells:
try:
ind, shell = find_shell_by_user_index(user_ind)
except KeyError:
raise Exception("Shell %i reference in group '%s' does not exist"%(user_ind, group['index'])
sh_inds.append(ind)
# If [Shell] section contains (potentiall conflicting) group parameters
# remove them and issue a warning
# First, required group parameters
for par in self.gr_required.keys():
try:
key = self.gr_required[par][0]
value = shell.pop(key)
mess = (" Redundant group parameter '%s' in [Shell] section"
" %i is discarded"%(par, user_ind))
issue_warning(mess)
except KeyError:
continue
# Second, optional group parameters
for par in self.gr_optional.keys():
try:
key = self.gr_optional[par][0]
value = shell.pop(key)
mess = (" Redundant group parameter '%s' in [Shell] section"
" %i is discarded"%(par, user_ind))
issue_warning(mess)
except KeyError:
continue
sh_refs_used = list(set(sh_inds))
sh_refs_used.sort()
# Check that all shells are referenced in the groups
assert sh_refs_used == range(self.nshells), "Some shells are not inside any of the groups"
################################################################################
#
@ -340,8 +441,9 @@ class ConfigParameters:
self.parse_shells()
self.parse_groups()
self.groups_shells_consistency()
# Output list of dictionaries
# Return a
output_pars = [{} for isec in xrange(nsections)]
for isec, section in enumerate(sections):
print "Section: %s"%(section)

View File

@ -228,6 +228,7 @@ class TestSpecialParsers(unittest.TestCase):
expected = {1: {'lshell': 2, 'ion_list': np.array([4, 5, 6, 7])},
2: {'lshell': 1, 'ion_list': np.array([0, 1, 2, 3]),
'tmatrix': np.array([[ 0., 1., 0.], [ 1., 0., 0.], [ 0., 0., 1.]])}}
# ...lousy way to test equality of two dictionaries containing numpy arrays
self.assertSetEqual(set(res.keys()), set(expected.keys()))
arr = res[1].pop('ion_list')
@ -257,12 +258,37 @@ class TestSpecialParsers(unittest.TestCase):
Scenarios:
- **if** no [Group] section exists and more than one [Shell] section
is given **raise** AssertionError
- **if** a [Group] section does not contain all required parameters
**raise** Exception
- **if** two correct [Shell] sections are defined
**return** a dictionary of shell parameters
- **if** a correct group section is defined **return** a list of dictionaries
"""
# Scenario 1
# conf_pars = ConfigParameters('test6.cfg')
# err_mess = "At least one group"
# with self.assertRaisesRegexp(AssertionError, err_mess):
# conf_pars.parse_shells()
################################################################################
#
# test_groups_shells_consistency()
#
################################################################################
def test_groups_shells_consistency(self):
"""
Function:
def groups_shells_consistency(self)
Scenarios:
- **if** no [Group] section exists and more than one [Shell] section
is given **raise** AssertionError
- **if** no [Group] section exists but the single [Shell] section
does not contain required group information **raise** KeyError
- **if** a shell referenced in a group does not exist
**raise** Exception
- **if** not all defined shells are referenced in the groups
**raise** Exception
"""
# Scenario 1
conf_pars = ConfigParameters('test6.cfg')
@ -271,6 +297,7 @@ class TestSpecialParsers(unittest.TestCase):
conf_pars.parse_shells()
if __name__ == '__main__':
suite = unittest.TestLoader().loadTestsFromTestCase(TestSpecialParsers)
# unittest.TextTestRunner(verbosity=2, buffer=False).run(suite)