You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1887 lines
64 KiB
1887 lines
64 KiB
2 years ago
|
#!/usr/bin/env python
|
||
|
"""
|
||
|
This file performs unit tests of functions within Exomerge.
|
||
|
|
||
|
Copyright 2018, 2021, 2022 National Technology and Engineering Solutions of Sandia. Under
|
||
|
the terms of Contract DE-NA-0003525, there is a non-exclusive license for use
|
||
|
of this work by or on behalf of the U.S. Government. Export of this program
|
||
|
may require a license from the United States Government.
|
||
|
|
||
|
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.
|
||
|
|
||
|
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 <http://www.gnu.org/licenses/>.
|
||
|
|
||
|
Author: Tim Kostka (tdkostk@sandia.gov)
|
||
|
Created: May 3, 2012
|
||
|
|
||
|
This module runs unit tests in a randomized fashion. To run:
|
||
|
|
||
|
$ python exomerge_unit_test.py 1000
|
||
|
|
||
|
Although the tests performed and randomly generated, since the random number is
|
||
|
seeded with a static value, the *same* sequence of randomly generated tests is
|
||
|
run each time. Processor speed can dictate how many tests are run, so setting
|
||
|
min_tests and max_tests to the same value or calling this script with an
|
||
|
argument can be used to prevent this.
|
||
|
|
||
|
"""
|
||
|
|
||
|
# standard libraries
|
||
|
import random
|
||
|
import inspect
|
||
|
import time
|
||
|
import copy
|
||
|
import os
|
||
|
import sys
|
||
|
import re
|
||
|
import math
|
||
|
|
||
|
# import the exomerge module
|
||
|
ACCESS = os.getenv("ACCESS", "@ACCESSDIR@")
|
||
|
sys.path.append(os.path.join(ACCESS, "lib"))
|
||
|
import exomerge
|
||
|
|
||
|
|
||
|
def _random_element(the_list):
|
||
|
"""
|
||
|
Return a random element from the list or None if none exist.
|
||
|
|
||
|
"""
|
||
|
if not the_list:
|
||
|
return None
|
||
|
return the_list[random.randint(0, len(the_list) - 1)]
|
||
|
|
||
|
|
||
|
def _random_boolean():
|
||
|
"""
|
||
|
Return one of True or False at random.
|
||
|
|
||
|
"""
|
||
|
return [True, False][random.randint(0, 1)]
|
||
|
|
||
|
|
||
|
def _random_subset(the_list, count=None):
|
||
|
"""
|
||
|
Return a random subset of elements from the list.
|
||
|
|
||
|
"""
|
||
|
if count is None:
|
||
|
if len(the_list) == 0:
|
||
|
count = 0
|
||
|
else:
|
||
|
count = random.randint(1, len(the_list))
|
||
|
return random.sample(the_list, count)
|
||
|
|
||
|
|
||
|
def _random_scalar():
|
||
|
"""
|
||
|
Return a random scalar.
|
||
|
|
||
|
"""
|
||
|
return random.uniform(0.5, 2)
|
||
|
|
||
|
|
||
|
def _random_vector():
|
||
|
"""
|
||
|
Return a random vector.
|
||
|
|
||
|
"""
|
||
|
vector = [_random_scalar() for _ in range(3)]
|
||
|
return vector
|
||
|
|
||
|
|
||
|
def _new_id():
|
||
|
"""
|
||
|
Return a new id.
|
||
|
|
||
|
"""
|
||
|
return random.randint(0, 9999)
|
||
|
|
||
|
|
||
|
def compares_equal_with_nan(one, two):
|
||
|
"""
|
||
|
Return True if the two objects are equal, assuming NaN == NaN.
|
||
|
|
||
|
Objects can include lists, dictionaries, floats, integers, strings, and/or
|
||
|
floats. They can be nested.
|
||
|
|
||
|
"""
|
||
|
if type(one) != type(two):
|
||
|
return False
|
||
|
if isinstance(one, dict):
|
||
|
if sorted(one.keys()) != sorted(two.keys()):
|
||
|
return False
|
||
|
return all(compares_equal_with_nan(one[x], two[x]) for x in list(one.keys()))
|
||
|
elif isinstance(one, list):
|
||
|
return len(one) == len(two) and all(
|
||
|
compares_equal_with_nan(x, y) for x, y in zip(one, two)
|
||
|
)
|
||
|
else:
|
||
|
# string, integer, or float
|
||
|
if isinstance(one, float):
|
||
|
return one == two or (math.isnan(one) and math.isnan(two))
|
||
|
else:
|
||
|
return one == two
|
||
|
|
||
|
|
||
|
class DummyFile(object):
|
||
|
"""Dummy class used to suppress output."""
|
||
|
|
||
|
def write(self, x):
|
||
|
"""Ignore the write command."""
|
||
|
pass
|
||
|
|
||
|
|
||
|
class OutputSuppression:
|
||
|
"""
|
||
|
This class is used to suppress output to stdout.
|
||
|
|
||
|
|
||
|
Example:
|
||
|
>>> std.stdout('Hello world!\n')
|
||
|
Hello world!
|
||
|
>>> print('Hello world!')
|
||
|
Hello world!
|
||
|
>>> with OutputSuppression():
|
||
|
>>> std.stdout('This will not appear\n')
|
||
|
>>> print('Hello world!')
|
||
|
|
||
|
"""
|
||
|
|
||
|
def __enter__(self):
|
||
|
"""Initialization routine."""
|
||
|
self.old_stdout = sys.stdout
|
||
|
sys.stdout = DummyFile()
|
||
|
|
||
|
def __exit__(self, type_, value, tracebackself):
|
||
|
"""Destructor routine."""
|
||
|
sys.stdout = self.old_stdout
|
||
|
|
||
|
|
||
|
class ExomergeUnitTester:
|
||
|
"""
|
||
|
A class to perform unit tests of the exomerge module.
|
||
|
|
||
|
"""
|
||
|
|
||
|
# identifiers used to create names
|
||
|
RANDOM_IDENTIFIERS = (
|
||
|
"abcdefghijklmnopqrstuvwxyz" "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "0123456789"
|
||
|
)
|
||
|
|
||
|
def __init__(self):
|
||
|
# store the exodus model
|
||
|
self.model = exomerge.ExodusModel()
|
||
|
# run tests for up to this amount of time in seconds
|
||
|
self.time_limit = 60
|
||
|
# run at least this many tests
|
||
|
self.min_tests = 3000
|
||
|
# run up to this many tests
|
||
|
self.max_tests = 3000
|
||
|
# only this many IO tests will be run
|
||
|
self.remaining_io_tests = 40
|
||
|
# set the maximum number of each object to prevent self.model from
|
||
|
# growing too large
|
||
|
self.maximum_objects = 10
|
||
|
|
||
|
def _random_identifier(self):
|
||
|
"""
|
||
|
Return a random name.
|
||
|
|
||
|
"""
|
||
|
return "".join([_random_element(self.RANDOM_IDENTIFIERS) for _ in range(6)])
|
||
|
|
||
|
def _random_timestep(self):
|
||
|
"""
|
||
|
Return a random timestep.
|
||
|
|
||
|
"""
|
||
|
if not self.model.timesteps:
|
||
|
return None
|
||
|
return random.choice(self.model.timesteps)
|
||
|
|
||
|
def _random_field_name(self):
|
||
|
"""
|
||
|
Return a random field name.
|
||
|
|
||
|
"""
|
||
|
return "field_" + self._random_identifier()
|
||
|
|
||
|
def _new_node_field_name(self):
|
||
|
"""
|
||
|
Return a new node field name.
|
||
|
|
||
|
"""
|
||
|
name = self._random_field_name()
|
||
|
while name in self.model.get_node_field_names():
|
||
|
name = self._random_field_name()
|
||
|
return name
|
||
|
|
||
|
def _new_global_variable_name(self):
|
||
|
"""
|
||
|
Return a new global variable name.
|
||
|
|
||
|
"""
|
||
|
name = self._random_field_name()
|
||
|
while name in self.model.get_global_variable_names():
|
||
|
name = self._random_field_name()
|
||
|
return name
|
||
|
|
||
|
def _new_element_field_name(self):
|
||
|
"""
|
||
|
Return a new element field name.
|
||
|
|
||
|
"""
|
||
|
name = self._random_field_name()
|
||
|
while name in self.model.get_element_field_names():
|
||
|
name = self._random_field_name()
|
||
|
return name
|
||
|
|
||
|
def _new_node_set_field_name(self):
|
||
|
"""
|
||
|
Return a new node set field name.
|
||
|
|
||
|
"""
|
||
|
name = self._random_field_name()
|
||
|
while name in self.model.get_node_set_field_names():
|
||
|
name = self._random_field_name()
|
||
|
return name
|
||
|
|
||
|
def _new_side_set_field_name(self):
|
||
|
"""
|
||
|
Return a new side set field name.
|
||
|
|
||
|
"""
|
||
|
name = self._random_field_name()
|
||
|
while name in self.model.get_side_set_field_names():
|
||
|
name = self._random_field_name()
|
||
|
return name
|
||
|
|
||
|
def _new_timestep(self):
|
||
|
"""
|
||
|
Return a new timestep.
|
||
|
|
||
|
"""
|
||
|
value = random.random()
|
||
|
while value in self.model.timesteps:
|
||
|
value = random.random()
|
||
|
return value
|
||
|
|
||
|
def _new_element_block_id(self):
|
||
|
"""
|
||
|
Return a new element block id.
|
||
|
|
||
|
"""
|
||
|
value = _new_id()
|
||
|
while value in self.model.get_element_block_ids():
|
||
|
value = _new_id()
|
||
|
return value
|
||
|
|
||
|
def _new_node_set_id(self):
|
||
|
"""
|
||
|
Return a new node set id.
|
||
|
|
||
|
"""
|
||
|
value = _new_id()
|
||
|
while value in self.model.get_node_set_ids():
|
||
|
value = _new_id()
|
||
|
return value
|
||
|
|
||
|
def _new_side_set_id(self):
|
||
|
"""
|
||
|
Return a new side set id.
|
||
|
|
||
|
"""
|
||
|
value = _new_id()
|
||
|
while value in self.model.get_side_set_ids():
|
||
|
value = _new_id()
|
||
|
return value
|
||
|
|
||
|
def _random_element_field_name(self):
|
||
|
"""
|
||
|
Return one element field name or None if none exist in the form
|
||
|
(id_, name).
|
||
|
|
||
|
"""
|
||
|
ids = self.model.get_element_block_ids()
|
||
|
random.shuffle(ids)
|
||
|
for id_ in ids:
|
||
|
fields = self.model._get_element_block_fields(id_)
|
||
|
names = list(fields.keys())
|
||
|
random.shuffle(names)
|
||
|
if names:
|
||
|
return (id_, names[0])
|
||
|
return None
|
||
|
|
||
|
def _random_node_field_name(self):
|
||
|
"""
|
||
|
Return one node field name or None.
|
||
|
|
||
|
"""
|
||
|
return _random_element(self.model.get_node_field_names())
|
||
|
|
||
|
def _random_node_set_field_name(self):
|
||
|
"""
|
||
|
Return one node set field name or None in the form (id_, name).
|
||
|
|
||
|
"""
|
||
|
ids = self.model.get_node_set_ids()
|
||
|
random.shuffle(ids)
|
||
|
for id_ in ids:
|
||
|
fields = self.model._get_node_set_fields(id_)
|
||
|
names = list(fields.keys())
|
||
|
random.shuffle(names)
|
||
|
if names:
|
||
|
return (id_, names[0])
|
||
|
return None
|
||
|
|
||
|
def _random_side_set_field_name(self):
|
||
|
"""
|
||
|
Return one side set field name or None in the form (id_, name).
|
||
|
|
||
|
"""
|
||
|
ids = self.model.get_side_set_ids()
|
||
|
random.shuffle(ids)
|
||
|
for id_ in ids:
|
||
|
fields = self.model._get_side_set_fields(id_)
|
||
|
names = list(fields.keys())
|
||
|
random.shuffle(names)
|
||
|
if names:
|
||
|
return (id_, names[0])
|
||
|
return None
|
||
|
|
||
|
def _random_global_variable_name(self):
|
||
|
"""
|
||
|
Return one global variable name or None.
|
||
|
|
||
|
"""
|
||
|
return _random_element(self.model.get_global_variable_names())
|
||
|
|
||
|
def _random_element_block_id(self):
|
||
|
"""Return a random element block id or name, or None if none exist."""
|
||
|
ids = self.model.get_element_block_ids()
|
||
|
ids.extend(self.model.get_all_element_block_names())
|
||
|
if not ids:
|
||
|
return None
|
||
|
return _random_element(ids)
|
||
|
|
||
|
def _random_element_block_ids(self):
|
||
|
"""Return a random subset of element block ids or names."""
|
||
|
ids = _random_subset(self.model.get_element_block_ids())
|
||
|
for i, id_ in enumerate(ids):
|
||
|
if random.randint(0, 1) == 0:
|
||
|
continue
|
||
|
name = self.model.get_element_block_name(id_)
|
||
|
if not name:
|
||
|
continue
|
||
|
ids[i] = name
|
||
|
return ids
|
||
|
|
||
|
def _random_side_set_id(self):
|
||
|
"""Return a random side set id or name, or None if none exist."""
|
||
|
ids = self.model.get_side_set_ids()
|
||
|
ids.extend(self.model.get_all_side_set_names())
|
||
|
return _random_element(ids)
|
||
|
|
||
|
def _random_side_set_ids(self):
|
||
|
"""Return a random subset of side set ids or name."""
|
||
|
ids = _random_subset(self.model.get_side_set_ids())
|
||
|
for i, id_ in enumerate(ids):
|
||
|
if random.randint(0, 1) == 0:
|
||
|
continue
|
||
|
name = self.model.get_side_set_name(id_)
|
||
|
if not name:
|
||
|
continue
|
||
|
ids[i] = name
|
||
|
return ids
|
||
|
|
||
|
def _random_node_set_id(self):
|
||
|
"""Return a random side set id or name, or None if none exist."""
|
||
|
ids = self.model.get_node_set_ids()
|
||
|
ids.extend(self.model.get_all_node_set_names())
|
||
|
return _random_element(ids)
|
||
|
|
||
|
def _random_node_set_ids(self):
|
||
|
"""Return a random subset of node set ids or name."""
|
||
|
ids = _random_subset(self.model.get_node_set_ids())
|
||
|
for i, id_ in enumerate(ids):
|
||
|
if random.randint(0, 1) == 0:
|
||
|
continue
|
||
|
name = self.model.get_node_set_name(id_)
|
||
|
if not name:
|
||
|
continue
|
||
|
ids[i] = name
|
||
|
return ids
|
||
|
|
||
|
def _truncate_element_blocks(self, number=None):
|
||
|
"""
|
||
|
Delete element blocks until only the given number exist.
|
||
|
|
||
|
"""
|
||
|
if number is None:
|
||
|
number = self.maximum_objects
|
||
|
objects = self.model.get_element_block_ids()
|
||
|
count = len(objects)
|
||
|
if count > number:
|
||
|
self.model.delete_element_block(_random_subset(objects, count - number))
|
||
|
|
||
|
def _truncate_timesteps(self, number=None):
|
||
|
"""
|
||
|
Delete timesteps until only the given number exist.
|
||
|
|
||
|
"""
|
||
|
if number is None:
|
||
|
number = self.maximum_objects
|
||
|
objects = self.model.get_timesteps()
|
||
|
count = len(objects)
|
||
|
if count > number:
|
||
|
self.model.delete_timestep(_random_subset(objects, count - number))
|
||
|
|
||
|
def _truncate_node_sets(self, number=None):
|
||
|
"""
|
||
|
Delete node sets until only the given number exist.
|
||
|
|
||
|
"""
|
||
|
if number is None:
|
||
|
number = self.maximum_objects
|
||
|
objects = self.model.get_node_set_ids()
|
||
|
count = len(objects)
|
||
|
if count > number:
|
||
|
self.model.delete_node_set(_random_subset(objects, count - number))
|
||
|
|
||
|
def _truncate_side_sets(self, number=None):
|
||
|
"""
|
||
|
Delete side sets until only the given number exist.
|
||
|
|
||
|
"""
|
||
|
if number is None:
|
||
|
number = self.maximum_objects
|
||
|
objects = self.model.get_side_set_ids()
|
||
|
count = len(objects)
|
||
|
if count > number:
|
||
|
self.model.delete_side_set(_random_subset(objects, count - number))
|
||
|
|
||
|
def _truncate_node_fields(self, number=None):
|
||
|
"""
|
||
|
Delete random node fields until only the given number exist.
|
||
|
|
||
|
"""
|
||
|
if number is None:
|
||
|
number = self.maximum_objects
|
||
|
objects = self.model.get_node_field_names()
|
||
|
count = len(objects)
|
||
|
if count > number:
|
||
|
self.model.delete_node_field(_random_subset(objects, count - number))
|
||
|
|
||
|
def _truncate_global_variables(self, number=None):
|
||
|
"""
|
||
|
Delete random global variables until only the given number exist.
|
||
|
|
||
|
"""
|
||
|
if number is None:
|
||
|
number = self.maximum_objects
|
||
|
objects = self.model.get_global_variable_names()
|
||
|
count = len(objects)
|
||
|
if count > number:
|
||
|
self.model.delete_global_variable(_random_subset(objects, count - number))
|
||
|
|
||
|
def _truncate_element_fields(self, number=None):
|
||
|
"""
|
||
|
Delete random element fields until only the given number exist.
|
||
|
|
||
|
"""
|
||
|
if number is None:
|
||
|
number = self.maximum_objects
|
||
|
while len(self.model.get_element_field_names()) > number:
|
||
|
(id_, name) = self._random_element_field_name()
|
||
|
self.model.delete_element_field(name, id_)
|
||
|
|
||
|
def _truncate_node_set_fields(self, number=None):
|
||
|
"""
|
||
|
Delete random node set fields until only the given number exist.
|
||
|
|
||
|
"""
|
||
|
if number is None:
|
||
|
number = self.maximum_objects
|
||
|
while len(self.model.get_node_set_field_names()) > number:
|
||
|
(id_, name) = self._random_node_set_field_name()
|
||
|
self.model.delete_node_set_field(name, id_)
|
||
|
|
||
|
def _truncate_side_set_fields(self, number=None):
|
||
|
"""
|
||
|
Delete random side set fields until only the given number exist.
|
||
|
|
||
|
"""
|
||
|
if number is None:
|
||
|
number = self.maximum_objects
|
||
|
while len(self.model.get_side_set_field_names()) > number:
|
||
|
(id_, name) = self._random_side_set_field_name()
|
||
|
self.model.delete_side_set_field(name, id_)
|
||
|
|
||
|
def _create_hex8_element_block(self, origin=None):
|
||
|
"""
|
||
|
Create a 2-element hex8 element block of dimension 2x1x1 with the
|
||
|
given minimum coordinates and return the element block id.
|
||
|
|
||
|
"""
|
||
|
new_nodes = [
|
||
|
[0.0, 0.0, 0.0],
|
||
|
[1.0, 0.0, 0.0],
|
||
|
[1.0, 1.0, 0.0],
|
||
|
[0.0, 1.0, 0.0],
|
||
|
[0.0, 0.0, 1.0],
|
||
|
[1.0, 0.0, 1.0],
|
||
|
[1.0, 1.0, 1.0],
|
||
|
[0.0, 1.0, 1.0],
|
||
|
[2.0, 0.0, 0.0],
|
||
|
[2.0, 1.0, 0.0],
|
||
|
[2.0, 0.0, 1.0],
|
||
|
[2.0, 1.0, 1.0],
|
||
|
]
|
||
|
if origin is None:
|
||
|
origin = [0, 0, 0]
|
||
|
new_nodes = [[x + y for x, y in zip(node, origin)] for node in new_nodes]
|
||
|
connectivity = list(range(8))
|
||
|
connectivity.extend([1, 8, 9, 2, 5, 10, 11, 6])
|
||
|
connectivity = [x + len(self.model.nodes) for x in connectivity]
|
||
|
self.model.create_nodes(new_nodes)
|
||
|
info = ["hex8", 2, 8, 0]
|
||
|
element_block_id = self._new_element_block_id()
|
||
|
self.model.create_element_block(element_block_id, info, connectivity)
|
||
|
return element_block_id
|
||
|
|
||
|
def _topology_test(self):
|
||
|
"""
|
||
|
Test the topology definitions to ensure they are consistent.
|
||
|
|
||
|
FACE_MAPPING, INVERTED_CONNECTIVITY, DIMENSION
|
||
|
|
||
|
"""
|
||
|
# see if keys are defined for all places
|
||
|
self.model._assert(
|
||
|
(
|
||
|
set(self.model.FACE_MAPPING.keys())
|
||
|
== set(self.model.INVERTED_CONNECTIVITY.keys())
|
||
|
)
|
||
|
)
|
||
|
self.model._assert(
|
||
|
(set(self.model.FACE_MAPPING.keys()) == set(self.model.DIMENSION.keys()))
|
||
|
)
|
||
|
self.model._assert(
|
||
|
(
|
||
|
set(self.model.FACE_MAPPING.keys())
|
||
|
== set(self.model.NODES_PER_ELEMENT.keys())
|
||
|
)
|
||
|
)
|
||
|
# faces should be 1 dimension less than their element
|
||
|
for element_type, face_list in list(self.model.FACE_MAPPING.items()):
|
||
|
element_dimension = self.model._get_dimension(element_type)
|
||
|
for face_type, _ in face_list:
|
||
|
self.model._assert(
|
||
|
self.model._get_dimension(face_type) + 1 == element_dimension
|
||
|
)
|
||
|
# all 2D elements should be able to be triangulated
|
||
|
for element_type in self.model.STANDARD_ELEMENT_TYPES:
|
||
|
if self.model.DIMENSION[element_type] == 2:
|
||
|
self.model._assert(element_type in self.model.TRIANGULATED_FACES)
|
||
|
|
||
|
# The following functions are unit tests of public functions within
|
||
|
# exomerge. For each public_function, a unit test of the name
|
||
|
# _test_public_function should exist here. If there is not a one to
|
||
|
# one mapping between the two, warning messages will appear when running
|
||
|
# this module.
|
||
|
#
|
||
|
# Tests should return None if successful (no return statement needed)
|
||
|
# Tests should return False if the test was unable to be run.
|
||
|
# Tests should raise an exception or exit(1) if unsuccessful.
|
||
|
|
||
|
def _test_calculate_element_volumes(self):
|
||
|
ids = self.model._get_standard_element_block_ids()
|
||
|
if not ids:
|
||
|
return False
|
||
|
if not self.model.timesteps:
|
||
|
self.model.create_timestep(0.0)
|
||
|
self.model.calculate_element_volumes(self._new_element_field_name(), ids)
|
||
|
|
||
|
def _test_get_element_block_centroid(self):
|
||
|
ids = self._random_element_block_ids()
|
||
|
if not ids:
|
||
|
return False
|
||
|
self.model.get_element_block_centroid(ids)
|
||
|
|
||
|
def _test_get_element_block_volume(self):
|
||
|
ids = self._random_element_block_ids()
|
||
|
if not ids:
|
||
|
return False
|
||
|
self.model.get_element_block_volume(ids)
|
||
|
|
||
|
def _test_convert_element_blocks(self):
|
||
|
id_ = _random_element(self.model._get_standard_element_block_ids())
|
||
|
if not id_:
|
||
|
return False
|
||
|
element_type = self.model._get_element_type(id_)
|
||
|
if element_type not in self.model.ELEMENT_CONVERSIONS:
|
||
|
return False
|
||
|
scheme = self.model.ELEMENT_CONVERSIONS[element_type]
|
||
|
if not scheme:
|
||
|
return False
|
||
|
new_element_type = _random_element(list(scheme.keys()))
|
||
|
self.model.convert_element_blocks(id_, new_element_type)
|
||
|
|
||
|
def _test_make_elements_linear(self):
|
||
|
ids = []
|
||
|
for id_ in self.model._get_standard_element_block_ids():
|
||
|
element_type = self.model._get_element_type(id_)
|
||
|
if self.model.ELEMENT_ORDER[element_type] == 1:
|
||
|
continue
|
||
|
if element_type not in self.model.ELEMENT_CONVERSIONS:
|
||
|
continue
|
||
|
scheme = self.model.ELEMENT_CONVERSIONS[element_type]
|
||
|
if 1 not in [self.model.ELEMENT_ORDER[x] for x in list(scheme.keys())]:
|
||
|
continue
|
||
|
ids.append(id_)
|
||
|
ids = _random_subset(ids)
|
||
|
if not ids:
|
||
|
return False
|
||
|
self.model.make_elements_linear(ids)
|
||
|
|
||
|
def _test_make_elements_quadratic(self):
|
||
|
ids = []
|
||
|
for id_ in self.model._get_standard_element_block_ids():
|
||
|
element_type = self.model._get_element_type(id_)
|
||
|
if self.model.ELEMENT_ORDER[element_type] == 2:
|
||
|
continue
|
||
|
if element_type not in self.model.ELEMENT_CONVERSIONS:
|
||
|
continue
|
||
|
scheme = self.model.ELEMENT_CONVERSIONS[element_type]
|
||
|
if 2 not in [self.model.ELEMENT_ORDER[x] for x in list(scheme.keys())]:
|
||
|
continue
|
||
|
ids.append(id_)
|
||
|
ids = _random_subset(ids)
|
||
|
if not ids:
|
||
|
return False
|
||
|
self.model.make_elements_quadratic(ids)
|
||
|
|
||
|
def _test_convert_hex8_block_to_tet4_block(self):
|
||
|
ids = [
|
||
|
x
|
||
|
for x in self.model.get_element_block_ids()
|
||
|
if self.model._get_element_type(x) == "hex8"
|
||
|
]
|
||
|
if not ids:
|
||
|
return False
|
||
|
self.model.convert_hex8_block_to_tet4_block(_random_element(ids))
|
||
|
|
||
|
def _test_duplicate_element_block(self):
|
||
|
old_id = self._random_element_block_id()
|
||
|
if old_id is None:
|
||
|
return False
|
||
|
new_id = self._new_element_block_id()
|
||
|
self.model.duplicate_element_block(old_id, new_id)
|
||
|
|
||
|
def _test_to_lowercase(self):
|
||
|
self.model.to_lowercase()
|
||
|
|
||
|
def _test_reflect_element_blocks(self):
|
||
|
id_ = self._create_hex8_element_block()
|
||
|
self.model.reflect_element_blocks(id_, [0, 0, 0], [1, -1, 0])
|
||
|
|
||
|
def _test_combine_element_blocks(self):
|
||
|
id_one = self._create_hex8_element_block()
|
||
|
id_two = self._create_hex8_element_block([2, 0, 0])
|
||
|
self.model.combine_element_blocks([id_one, id_two])
|
||
|
|
||
|
def _test_create_side_set_from_expression(self):
|
||
|
new_nodes = [
|
||
|
[0.0, 0.0, 0.0],
|
||
|
[1.0, 0.0, 0.0],
|
||
|
[1.0, 1.0, 0.0],
|
||
|
[0.0, 1.0, 0.0],
|
||
|
[0.0, 0.0, 1.0],
|
||
|
[1.0, 0.0, 1.0],
|
||
|
[1.0, 1.0, 1.0],
|
||
|
[0.0, 1.0, 1.0],
|
||
|
]
|
||
|
connectivity = list(range(8))
|
||
|
connectivity = [x + len(self.model.nodes) for x in connectivity]
|
||
|
self.model.create_nodes(new_nodes)
|
||
|
info = ["hex8", 1, 8, 0]
|
||
|
element_block_id = self._new_element_block_id()
|
||
|
self.model.create_element_block(element_block_id, info, connectivity)
|
||
|
self.model.create_side_set_from_expression(
|
||
|
self._new_side_set_id(),
|
||
|
"Z = 0 || Z == 1 || X == 1",
|
||
|
element_block_ids=element_block_id,
|
||
|
timesteps="none",
|
||
|
)
|
||
|
|
||
|
def _test_convert_side_set_to_cohesive_zone(self):
|
||
|
new_nodes = [
|
||
|
[0.0, 0.0, 0.0],
|
||
|
[1.0, 0.0, 0.0],
|
||
|
[1.0, 1.0, 0.0],
|
||
|
[0.0, 1.0, 0.0],
|
||
|
[0.0, 0.0, 1.0],
|
||
|
[1.0, 0.0, 1.0],
|
||
|
[1.0, 1.0, 1.0],
|
||
|
[0.0, 1.0, 1.0],
|
||
|
[2.0, 0.0, 0.0],
|
||
|
[2.0, 1.0, 0.0],
|
||
|
[2.0, 0.0, 1.0],
|
||
|
[2.0, 1.0, 1.0],
|
||
|
]
|
||
|
connectivity = list(range(8))
|
||
|
connectivity.extend([1, 8, 9, 2, 5, 10, 11, 6])
|
||
|
connectivity = [x + len(self.model.nodes) for x in connectivity]
|
||
|
self.model.create_nodes(new_nodes)
|
||
|
info = ["hex8", 2, 8, 0]
|
||
|
element_block_id = self._new_element_block_id()
|
||
|
self.model.create_element_block(element_block_id, info, connectivity)
|
||
|
side_set_id = self._new_side_set_id()
|
||
|
self.model.create_side_set(side_set_id, [(element_block_id, 1, 3)])
|
||
|
self.model.convert_side_set_to_cohesive_zone(
|
||
|
side_set_id, self._new_element_block_id()
|
||
|
)
|
||
|
|
||
|
def _test_calculate_global_variable(self):
|
||
|
if not self.model.timesteps:
|
||
|
self.model.create_timestep(0.0)
|
||
|
variable_names = set(["time"])
|
||
|
variable_names.update(self.model.get_global_variable_names())
|
||
|
expression = "%s = %s" % (
|
||
|
self._new_global_variable_name(),
|
||
|
" + ".join(variable_names),
|
||
|
)
|
||
|
self.model.calculate_global_variable(expression)
|
||
|
|
||
|
def _test_calculate_node_field(self):
|
||
|
if not self.model.timesteps:
|
||
|
self.model.create_timestep(0.0)
|
||
|
variable_names = set(["time"])
|
||
|
variable_names.update(self.model.get_global_variable_names())
|
||
|
variable_names.update(self.model.get_node_field_names())
|
||
|
expression = "%s = %s" % (
|
||
|
self._new_node_field_name(),
|
||
|
" + ".join(variable_names),
|
||
|
)
|
||
|
self.model.calculate_node_field(expression)
|
||
|
|
||
|
def _test_calculate_element_field(self):
|
||
|
if not self.model.timesteps:
|
||
|
self.model.create_timestep(0.0)
|
||
|
info = self._random_element_field_name()
|
||
|
if info is None:
|
||
|
return False
|
||
|
(id_, _) = info
|
||
|
variable_names = set(["time"])
|
||
|
variable_names.update(self.model.get_global_variable_names())
|
||
|
variable_names.update(self.model.get_element_field_names(id_))
|
||
|
expression = "%s = %s" % (
|
||
|
self._new_element_field_name(),
|
||
|
" + ".join(variable_names),
|
||
|
)
|
||
|
self.model.calculate_element_field(expression, id_)
|
||
|
|
||
|
def _test_calculate_element_field_maximum(self):
|
||
|
info = self._random_element_field_name()
|
||
|
if info is None or len(info[1]) + 13 > 32:
|
||
|
return False
|
||
|
if not self.model.timesteps:
|
||
|
self.model.create_timestep(0.0)
|
||
|
(id_, name) = info
|
||
|
block_ids = [
|
||
|
x
|
||
|
for x in self.model.get_element_block_ids()
|
||
|
if self.model.element_field_exists(name, x)
|
||
|
]
|
||
|
block_ids = _random_subset(block_ids)
|
||
|
if self.model.get_element_count(block_ids) == 0:
|
||
|
return False
|
||
|
self.model.delete_global_variables(name + "_*")
|
||
|
self.model.calculate_element_field_maximum(
|
||
|
name,
|
||
|
element_block_ids=block_ids,
|
||
|
calculate_location=_random_boolean(),
|
||
|
calculate_block_id=_random_boolean(),
|
||
|
)
|
||
|
|
||
|
def _test_calculate_element_field_minimum(self):
|
||
|
info = self._random_element_field_name()
|
||
|
if info is None or len(info[1]) + 13 > 32:
|
||
|
return False
|
||
|
if not self.model.timesteps:
|
||
|
self.model.create_timestep(0.0)
|
||
|
(id_, name) = info
|
||
|
block_ids = [
|
||
|
x
|
||
|
for x in self.model.get_element_block_ids()
|
||
|
if self.model.element_field_exists(name, x)
|
||
|
]
|
||
|
block_ids = _random_subset(block_ids)
|
||
|
if self.model.get_element_count(block_ids) == 0:
|
||
|
return False
|
||
|
self.model.delete_global_variables(name + "_*")
|
||
|
self.model.calculate_element_field_minimum(
|
||
|
name,
|
||
|
element_block_ids=block_ids,
|
||
|
calculate_location=_random_boolean(),
|
||
|
calculate_block_id=_random_boolean(),
|
||
|
)
|
||
|
|
||
|
def _test_calculate_node_field_minimum(self):
|
||
|
if not self.model.nodes:
|
||
|
return False
|
||
|
if not self.model.timesteps:
|
||
|
self.model.create_timestep(0.0)
|
||
|
name = self._random_node_field_name()
|
||
|
if name is None or len(name) + 6 > 32:
|
||
|
return False
|
||
|
self.model.delete_global_variables(name + "_*")
|
||
|
if _random_boolean():
|
||
|
self.model.calculate_node_field_minimum(
|
||
|
name, calculate_location=_random_boolean()
|
||
|
)
|
||
|
else:
|
||
|
block_ids = self._random_element_block_ids()
|
||
|
if not self.model.get_nodes_in_element_block(block_ids):
|
||
|
return False
|
||
|
self.model.calculate_node_field_minimum(
|
||
|
name, element_block_ids=block_ids, calculate_location=_random_boolean()
|
||
|
)
|
||
|
|
||
|
def _test_calculate_node_field_maximum(self):
|
||
|
if not self.model.nodes:
|
||
|
return False
|
||
|
if not self.model.timesteps:
|
||
|
self.model.create_timestep(0.0)
|
||
|
name = self._random_node_field_name()
|
||
|
if name is None or len(name) + 6 > 32:
|
||
|
return False
|
||
|
self.model.delete_global_variables(name + "_*")
|
||
|
self.model.calculate_node_field_maximum(
|
||
|
name, calculate_location=_random_boolean()
|
||
|
)
|
||
|
|
||
|
def _test_output_global_variables(self):
|
||
|
filename = "temp.csv" if _random_boolean() else None
|
||
|
if self.remaining_io_tests <= 0:
|
||
|
filename = None
|
||
|
if filename is not None:
|
||
|
self.remaining_io_tests -= 1
|
||
|
with OutputSuppression():
|
||
|
self.model.output_global_variables(filename)
|
||
|
if filename:
|
||
|
os.remove(filename)
|
||
|
|
||
|
def _test_calculate_node_set_field(self):
|
||
|
info = self._random_node_set_field_name()
|
||
|
if info is None:
|
||
|
return False
|
||
|
if not self.model.timesteps:
|
||
|
self.model.create_timestep(0.0)
|
||
|
(id_, name) = info
|
||
|
variable_names = set(["time"])
|
||
|
variable_names.update(self.model.get_global_variable_names())
|
||
|
variable_names.update(self.model.get_node_field_names())
|
||
|
variable_names.update(self.model.get_node_set_field_names(id_))
|
||
|
expression = "%s = %s" % (
|
||
|
self._new_node_set_field_name(),
|
||
|
" + ".join(variable_names),
|
||
|
)
|
||
|
self.model.calculate_node_set_field(expression, id_)
|
||
|
|
||
|
def _test_calculate_side_set_field(self):
|
||
|
info = self._random_side_set_field_name()
|
||
|
if info is None:
|
||
|
return False
|
||
|
if not self.model.timesteps:
|
||
|
self.model.create_timestep(0.0)
|
||
|
(id_, name) = info
|
||
|
variable_names = set(["time"])
|
||
|
variable_names.update(self.model.get_global_variable_names())
|
||
|
variable_names.update(self.model.get_side_set_field_names(id_))
|
||
|
expression = "%s = %s" % (
|
||
|
self._new_side_set_field_name(),
|
||
|
" + ".join(variable_names),
|
||
|
)
|
||
|
self.model.calculate_side_set_field(expression, id_)
|
||
|
|
||
|
def _test_merge_nodes(self):
|
||
|
if not self.model.nodes:
|
||
|
return False
|
||
|
x = len(self.model.nodes)
|
||
|
self.model._duplicate_nodes(_random_subset(list(range(len(self.model.nodes))), 1), [])
|
||
|
self.model.merge_nodes(suppress_warnings=True)
|
||
|
assert len(self.model.nodes) <= x
|
||
|
|
||
|
def _test_unmerge_element_blocks(self):
|
||
|
if len(self.model.element_blocks) < 2:
|
||
|
return False
|
||
|
(id1, id2) = _random_subset(self.model.get_element_block_ids(), count=2)
|
||
|
connectivity_1 = self.model.get_connectivity(id1)
|
||
|
connectivity_2 = self.model.get_connectivity(id2)
|
||
|
if not connectivity_1 or not connectivity_2:
|
||
|
return False
|
||
|
connectivity_2[0] = connectivity_1[0]
|
||
|
self.model.unmerge_element_blocks([id1, id2])
|
||
|
assert not (
|
||
|
set(self.model.get_connectivity(id1))
|
||
|
& set(self.model.get_connectivity(id2))
|
||
|
)
|
||
|
|
||
|
def _test_get_length_scale(self):
|
||
|
self.model.get_length_scale()
|
||
|
|
||
|
def _test_get_input_deck(self):
|
||
|
self.model.info_records = [
|
||
|
"asdf",
|
||
|
"begin",
|
||
|
" begin statement",
|
||
|
" end statement",
|
||
|
"end sierra",
|
||
|
"other stuff",
|
||
|
]
|
||
|
assert len(self.model.get_input_deck().split("\n")) == 4
|
||
|
|
||
|
def _test_create_interpolated_timestep(self):
|
||
|
if len(self.model.timesteps) < 2:
|
||
|
return False
|
||
|
steps = self.model.get_timesteps()
|
||
|
new_time = steps[0] + random.random() * (steps[-1] - steps[0])
|
||
|
if self.model.timestep_exists(new_time):
|
||
|
return False
|
||
|
self.model.create_interpolated_timestep(new_time)
|
||
|
|
||
|
def _test_rename_element_block(self):
|
||
|
id_ = self._random_element_block_id()
|
||
|
if id_ is None:
|
||
|
return False
|
||
|
self.model.rename_element_block(id_, self._new_element_block_id())
|
||
|
|
||
|
def _test_rename_side_set(self):
|
||
|
id_ = self._random_side_set_id()
|
||
|
if id_ is None:
|
||
|
return False
|
||
|
self.model.rename_side_set(id_, self._new_side_set_id())
|
||
|
|
||
|
def _test_rename_node_set(self):
|
||
|
id_ = self._random_node_set_id()
|
||
|
if id_ is None:
|
||
|
return False
|
||
|
self.model.rename_node_set(id_, self._new_node_set_id())
|
||
|
|
||
|
def _test_rename_global_variable(self):
|
||
|
name = self._random_global_variable_name()
|
||
|
if name is None:
|
||
|
return False
|
||
|
self.model.rename_global_variable(name, self._new_global_variable_name())
|
||
|
|
||
|
def _test_rename_node_field(self):
|
||
|
name = self._random_node_field_name()
|
||
|
if name is None:
|
||
|
return False
|
||
|
self.model.rename_node_field(name, self._new_node_field_name())
|
||
|
|
||
|
def _test_rename_node_set_field(self):
|
||
|
info = self._random_node_set_field_name()
|
||
|
if info is None:
|
||
|
return False
|
||
|
(id_, name) = info
|
||
|
self.model.rename_node_set_field(name, self._new_node_set_field_name(), id_)
|
||
|
|
||
|
def _test_rename_side_set_field(self):
|
||
|
info = self._random_side_set_field_name()
|
||
|
if info is None:
|
||
|
return False
|
||
|
(id_, name) = info
|
||
|
self.model.rename_side_set_field(name, self._new_side_set_field_name(), id_)
|
||
|
|
||
|
def _test_delete_node_set_field(self):
|
||
|
info = self._random_node_set_field_name()
|
||
|
if info is None:
|
||
|
self._test_create_node_set_field()
|
||
|
info = self._random_node_set_field_name()
|
||
|
if info is None:
|
||
|
return False
|
||
|
(id_, name) = info
|
||
|
self.model.delete_node_set_field(name, id_)
|
||
|
|
||
|
def _test_delete_side_set_field(self):
|
||
|
info = self._random_side_set_field_name()
|
||
|
if info is None:
|
||
|
return False
|
||
|
(id_, name) = info
|
||
|
self.model.delete_side_set_field(name, id_)
|
||
|
|
||
|
def _test_calculate_element_centroids(self):
|
||
|
if not self.model.element_blocks:
|
||
|
return False
|
||
|
if not self.model.timesteps:
|
||
|
self.model.create_timestep(0.0)
|
||
|
for id_ in self.model.get_element_block_ids():
|
||
|
for name in ["centroid_x", "centroid_y", "centroid_z"]:
|
||
|
if self.model.element_field_exists(name, id_):
|
||
|
self.model.delete_element_field(name, id_)
|
||
|
self.model.calculate_element_centroids()
|
||
|
self._truncate_element_fields()
|
||
|
|
||
|
def _test_convert_element_field_to_node_field(self):
|
||
|
field = self._random_element_field_name()
|
||
|
if field is None:
|
||
|
return False
|
||
|
if not self.model.timesteps:
|
||
|
self.model.create_timestep(0.0)
|
||
|
self.model.convert_element_field_to_node_field(
|
||
|
field[1], self._new_node_field_name()
|
||
|
)
|
||
|
self._truncate_node_fields()
|
||
|
|
||
|
def _test_convert_node_field_to_element_field(self):
|
||
|
field = self._random_node_field_name()
|
||
|
if field is None:
|
||
|
return False
|
||
|
if not self.model.timesteps:
|
||
|
self.model.create_timestep(0.0)
|
||
|
self.model.convert_node_field_to_element_field(
|
||
|
field, self._new_element_field_name()
|
||
|
)
|
||
|
self._truncate_element_fields()
|
||
|
|
||
|
def _test_create_averaged_element_field(self):
|
||
|
self._truncate_element_fields()
|
||
|
id_ = self._random_element_block_id()
|
||
|
if id_ is None:
|
||
|
return False
|
||
|
field_names = self.model.get_element_field_names(id_)
|
||
|
if not field_names:
|
||
|
return False
|
||
|
if not self.model.timesteps:
|
||
|
self.model.create_timestep(0.0)
|
||
|
field = _random_subset(field_names)
|
||
|
self.model.create_averaged_element_field(
|
||
|
field, self._new_element_field_name(), id_
|
||
|
)
|
||
|
|
||
|
def _test_create_displacement_field(self):
|
||
|
if not self.model.timesteps:
|
||
|
self.model.create_timestep(0.0)
|
||
|
self.model.create_displacement_field()
|
||
|
self._truncate_node_fields()
|
||
|
|
||
|
def _test_create_element_block(self):
|
||
|
for _ in range(random.randint(1, self.maximum_objects)):
|
||
|
new_nodes = [
|
||
|
[0.0, 0.0, 0.0],
|
||
|
[1.0, 0.0, 0.0],
|
||
|
[1.0, 1.0, 0.0],
|
||
|
[0.0, 1.0, 0.0],
|
||
|
[0.0, 0.0, 1.0],
|
||
|
[0.0, 0.0, 1.0],
|
||
|
[0.0, 1.0, 1.0],
|
||
|
[0.0, 1.0, 1.0],
|
||
|
[2.0, 0.0, 0.0],
|
||
|
[2.0, 1.0, 0.0],
|
||
|
[2.0, 0.0, 1.0],
|
||
|
[2.0, 1.0, 1.0],
|
||
|
]
|
||
|
connectivity = list(range(8))
|
||
|
connectivity.extend([1, 8, 9, 2, 5, 10, 11, 6])
|
||
|
connectivity = [x + len(self.model.nodes) for x in connectivity]
|
||
|
self.model.create_nodes(new_nodes)
|
||
|
info = ["hex8", 2, 8, 0]
|
||
|
self.model.create_element_block(
|
||
|
self._new_element_block_id(), info, connectivity
|
||
|
)
|
||
|
self._truncate_element_blocks()
|
||
|
|
||
|
def _test_create_element_field(self):
|
||
|
if not self.model.timesteps:
|
||
|
self.model.create_timestep(0.0)
|
||
|
for _ in range(random.randint(1, self.maximum_objects)):
|
||
|
ids = self._random_element_block_ids()
|
||
|
if ids:
|
||
|
self.model.create_element_field(
|
||
|
self._new_element_field_name(), ids, random.random()
|
||
|
)
|
||
|
self._truncate_element_fields()
|
||
|
|
||
|
def _test_create_global_variable(self):
|
||
|
for _ in range(random.randint(1, self.maximum_objects)):
|
||
|
self.model.create_global_variable(self._new_global_variable_name())
|
||
|
self._truncate_global_variables()
|
||
|
|
||
|
def _test_create_node_field(self):
|
||
|
if not self.model.timesteps:
|
||
|
self.model.create_timestep(0.0)
|
||
|
for _ in range(random.randint(1, self.maximum_objects)):
|
||
|
self.model.create_node_field(self._new_node_field_name(), random.random())
|
||
|
self._truncate_node_fields()
|
||
|
|
||
|
def _test_add_nodes_to_node_set(self):
|
||
|
self._truncate_node_sets()
|
||
|
if not self.model.nodes or not self.model.node_sets:
|
||
|
return False
|
||
|
id_ = self._random_node_set_id()
|
||
|
current_members = self.model.get_node_set_members(id_)
|
||
|
members = [random.randint(0, len(self.model.nodes) - 1) for _ in range(20)]
|
||
|
members = sorted(set(members))
|
||
|
new_members = []
|
||
|
for member in members:
|
||
|
if member not in current_members:
|
||
|
new_members.append(member)
|
||
|
self.model.add_nodes_to_node_set(id_, new_members)
|
||
|
|
||
|
def _test_create_node_set(self):
|
||
|
if not self.model.nodes:
|
||
|
return False
|
||
|
for _ in range(random.randint(1, self.maximum_objects)):
|
||
|
members = [random.randint(0, len(self.model.nodes) - 1) for _ in range(20)]
|
||
|
members = sorted(set(members))
|
||
|
self.model.create_node_set(self._new_node_set_id(), members)
|
||
|
self._truncate_node_sets()
|
||
|
|
||
|
def _test_create_node_set_field(self):
|
||
|
for _ in range(random.randint(1, self.maximum_objects)):
|
||
|
id_ = self._random_node_set_id()
|
||
|
if id_ is None:
|
||
|
return False
|
||
|
if not self.model.timesteps:
|
||
|
self.model.create_timestep(0.0)
|
||
|
self.model.create_node_set_field(
|
||
|
self._new_node_set_field_name(), id_, random.random()
|
||
|
)
|
||
|
self._truncate_node_set_fields()
|
||
|
|
||
|
def _test_create_node_set_from_side_set(self):
|
||
|
id_ = self._random_side_set_id()
|
||
|
if id_ is not None:
|
||
|
self.model.create_node_set_from_side_set(self._new_node_set_id(), id_)
|
||
|
self._truncate_node_sets()
|
||
|
|
||
|
def _test_create_nodes(self):
|
||
|
new_nodes = []
|
||
|
for _ in range(7):
|
||
|
new_nodes.append([random.random() for _ in range(3)])
|
||
|
self.model.create_nodes(new_nodes)
|
||
|
|
||
|
def _test_create_side_set(self):
|
||
|
if not self.model.element_blocks:
|
||
|
return False
|
||
|
for _ in range(random.randint(1, self.maximum_objects)):
|
||
|
members = []
|
||
|
for _ in range(20):
|
||
|
id_ = _random_element(self.model.get_element_block_ids())
|
||
|
element_count = self.model.get_element_count(id_)
|
||
|
if element_count == 0:
|
||
|
continue
|
||
|
element_index = random.randint(0, element_count - 1)
|
||
|
side_index = random.randint(0, 3)
|
||
|
members.append((id_, element_index, side_index))
|
||
|
members = sorted(set(members))
|
||
|
self.model.create_side_set(self._new_side_set_id(), members)
|
||
|
self._truncate_side_sets()
|
||
|
|
||
|
def _test_add_faces_to_side_set(self):
|
||
|
self._truncate_side_sets()
|
||
|
if not self.model.element_blocks:
|
||
|
return False
|
||
|
if not self.model.side_sets:
|
||
|
return False
|
||
|
members = []
|
||
|
for _ in range(20):
|
||
|
id_ = _random_element(self.model.get_element_block_ids())
|
||
|
element_count = self.model.get_element_count(id_)
|
||
|
if element_count == 0:
|
||
|
continue
|
||
|
element_index = random.randint(0, element_count - 1)
|
||
|
side_index = random.randint(0, 3)
|
||
|
members.append((id_, element_index, side_index))
|
||
|
members = sorted(set(members))
|
||
|
id_ = self._random_side_set_id()
|
||
|
current_members = self.model.get_side_set_members(id_)
|
||
|
new_members = []
|
||
|
for member in members:
|
||
|
if member not in current_members:
|
||
|
new_members.append(member)
|
||
|
self.model.add_faces_to_side_set(id_, new_members)
|
||
|
|
||
|
def _test_create_side_set_field(self):
|
||
|
for _ in range(random.randint(1, self.maximum_objects)):
|
||
|
id_ = self._random_side_set_id()
|
||
|
if id_ is None:
|
||
|
return False
|
||
|
if not self.model.timesteps:
|
||
|
self.model.create_timestep(0.0)
|
||
|
self.model.create_side_set_field(
|
||
|
self._new_side_set_field_name(), id_, random.random()
|
||
|
)
|
||
|
self._truncate_side_set_fields()
|
||
|
|
||
|
def _test_create_timestep(self):
|
||
|
for _ in range(random.randint(1, self.maximum_objects)):
|
||
|
self.model.create_timestep(self._new_timestep())
|
||
|
self._truncate_timesteps()
|
||
|
|
||
|
def _test_copy_timestep(self):
|
||
|
step = self._random_timestep()
|
||
|
if step is None:
|
||
|
return False
|
||
|
self.model.copy_timestep(step, self._new_timestep())
|
||
|
self._truncate_timesteps()
|
||
|
|
||
|
def _test_delete_element_block(self):
|
||
|
ids = self._random_element_block_ids()
|
||
|
if not ids:
|
||
|
return False
|
||
|
self.model.delete_element_block(ids)
|
||
|
|
||
|
def _test_delete_element_field(self):
|
||
|
names = _random_subset(self.model.get_element_field_names())
|
||
|
if not names:
|
||
|
return False
|
||
|
self.model.delete_element_field(names)
|
||
|
|
||
|
def _test_delete_empty_node_sets(self):
|
||
|
self.model.create_node_set(self._new_node_set_id(), [])
|
||
|
self.model.delete_empty_node_sets()
|
||
|
|
||
|
def _test_delete_empty_side_sets(self):
|
||
|
self.model.create_side_set(self._new_side_set_id(), [])
|
||
|
self.model.delete_empty_side_sets()
|
||
|
|
||
|
def _test_delete_global_variable(self):
|
||
|
names = _random_subset(self.model.get_global_variable_names())
|
||
|
if not names:
|
||
|
return False
|
||
|
self.model.delete_global_variable(names)
|
||
|
|
||
|
def _test_delete_node_field(self):
|
||
|
names = _random_subset(self.model.get_node_field_names())
|
||
|
if not names:
|
||
|
return False
|
||
|
self.model.delete_node_field(names)
|
||
|
|
||
|
def _test_delete_node_set(self):
|
||
|
ids = self._random_node_set_ids()
|
||
|
if not ids:
|
||
|
return False
|
||
|
self.model.delete_node_set(ids)
|
||
|
|
||
|
def _test_delete_side_set(self):
|
||
|
ids = self._random_side_set_ids()
|
||
|
if not ids:
|
||
|
return False
|
||
|
self.model.delete_side_set(ids)
|
||
|
|
||
|
def _test_delete_timestep(self):
|
||
|
times = _random_subset(self.model.get_timesteps())
|
||
|
if not times:
|
||
|
return False
|
||
|
self.model.delete_timestep(times)
|
||
|
|
||
|
def _test_delete_unused_nodes(self):
|
||
|
self.model.create_nodes([[0.0, 0.0, 0.0], [1.0, 0.0, 0.0]])
|
||
|
node_count = len(self.model.nodes)
|
||
|
self.model.delete_unused_nodes()
|
||
|
assert len(self.model.nodes) <= node_count - 2
|
||
|
|
||
|
def _test_displace_element_blocks(self):
|
||
|
ids = self._random_element_block_ids()
|
||
|
if not ids:
|
||
|
return False
|
||
|
if not self.model.timesteps:
|
||
|
return False
|
||
|
self.model.unmerge_element_blocks()
|
||
|
self.model.displace_element_blocks(ids, _random_vector())
|
||
|
|
||
|
def _test_displacement_field_exists(self):
|
||
|
self.model.displacement_field_exists()
|
||
|
|
||
|
def _test_element_block_exists(self):
|
||
|
id_ = self._random_element_block_id()
|
||
|
if id_ is None:
|
||
|
assert not self.model.element_block_exists(0)
|
||
|
else:
|
||
|
assert self.model.element_block_exists(id_)
|
||
|
|
||
|
def _test_element_field_exists(self):
|
||
|
id_ = self._random_element_block_id()
|
||
|
if not id_:
|
||
|
return False
|
||
|
name = _random_element(self.model.get_element_field_names(id_))
|
||
|
if name is None:
|
||
|
assert not self.model.element_field_exists("temp", id_)
|
||
|
else:
|
||
|
assert self.model.element_field_exists(name, id_)
|
||
|
|
||
|
def _test_export_model(self):
|
||
|
if self.remaining_io_tests <= 0:
|
||
|
return False
|
||
|
self.remaining_io_tests -= 1
|
||
|
self.model.export_model("temp.e")
|
||
|
# make sure the exported model is equal
|
||
|
model2 = exomerge.import_model("temp.e")
|
||
|
model2.qa_records = model2.qa_records[:-1]
|
||
|
one = self.model
|
||
|
two = model2
|
||
|
assert one.nodes == two.nodes
|
||
|
assert one.timesteps == two.timesteps
|
||
|
# There is some odd bug here where characters get added sometimes
|
||
|
# but not often. To avoid this, we don't compare info records. This
|
||
|
# does not appear to be a bug within exomerge.py or exodus.py. It may
|
||
|
# be within ctypes, but more likely is within the exodus library
|
||
|
# itself.
|
||
|
# exported: ['asdf', 'begin', ' begin statement', ...]
|
||
|
# imported: ['asdf\x7f\xf8', 'begin', ' begin statement', ...]
|
||
|
# assert one.info_records == two.info_records
|
||
|
assert one.title == two.title
|
||
|
assert one.qa_records == two.qa_records
|
||
|
assert one.title == two.title
|
||
|
assert compares_equal_with_nan(one.node_fields, two.node_fields)
|
||
|
assert compares_equal_with_nan(one.global_variables, two.global_variables)
|
||
|
assert compares_equal_with_nan(one.side_sets, two.side_sets)
|
||
|
assert compares_equal_with_nan(one.node_sets, two.node_sets)
|
||
|
# There is a bug/feature within exodus.py where element types are
|
||
|
# renamed to uppercase. To avoid this, we don't compare the info
|
||
|
# field within each block
|
||
|
for id_ in list(one.element_blocks.keys()):
|
||
|
assert compares_equal_with_nan(
|
||
|
one.element_blocks[id_][0], two.element_blocks[id_][0]
|
||
|
)
|
||
|
# assert compares_equal_with_nan(one.element_blocks[id_][1],
|
||
|
# two.element_blocks[id_][1])
|
||
|
assert compares_equal_with_nan(
|
||
|
one.element_blocks[id_][2], two.element_blocks[id_][2]
|
||
|
)
|
||
|
assert compares_equal_with_nan(
|
||
|
one.element_blocks[id_][3], two.element_blocks[id_][3]
|
||
|
)
|
||
|
os.remove("temp.e")
|
||
|
|
||
|
def _test_export_stl_file(self):
|
||
|
if self.remaining_io_tests <= 0:
|
||
|
return False
|
||
|
self.remaining_io_tests -= 1
|
||
|
self.model.export_stl_file("temp.stl")
|
||
|
os.remove("temp.stl")
|
||
|
|
||
|
def _test_export_wrl_model(self):
|
||
|
if self.remaining_io_tests <= 0:
|
||
|
return False
|
||
|
self.remaining_io_tests -= 1
|
||
|
if not self.model.timesteps:
|
||
|
self.model.create_timestep(0.0)
|
||
|
if not self.model.element_blocks:
|
||
|
self._create_hex8_element_block()
|
||
|
node_field_name = self._new_node_field_name()
|
||
|
self.model.calculate_node_field(node_field_name + " = X + Y + Z")
|
||
|
self.model.export_wrl_model("temp.wrl", node_field_name)
|
||
|
os.remove("temp.wrl")
|
||
|
os.remove("temp_wrl.e")
|
||
|
|
||
|
def _test_export(self):
|
||
|
if self.remaining_io_tests <= 0:
|
||
|
return False
|
||
|
self.remaining_io_tests -= 1
|
||
|
filename = "temp." + _random_element(["e", "stl"])
|
||
|
self.model.export(filename)
|
||
|
os.remove(filename)
|
||
|
|
||
|
def _test_get_element_block_connectivity(self):
|
||
|
id_ = self._random_element_block_id()
|
||
|
if id_ is None:
|
||
|
return False
|
||
|
self.model.get_element_block_connectivity(id_)
|
||
|
|
||
|
def _test_get_nodes_per_element(self):
|
||
|
id_ = self._random_element_block_id()
|
||
|
if id_ is None:
|
||
|
return False
|
||
|
self.model.get_nodes_per_element(id_)
|
||
|
|
||
|
def _test_get_element_block_ids(self):
|
||
|
self.model.get_element_block_ids()
|
||
|
|
||
|
def _test_get_element_count(self):
|
||
|
ids = self._random_element_block_ids()
|
||
|
if ids is None:
|
||
|
return False
|
||
|
self.model.get_element_count(ids)
|
||
|
|
||
|
def _test_get_element_field_names(self):
|
||
|
ids = self._random_element_block_ids()
|
||
|
if ids is None:
|
||
|
return False
|
||
|
self.model.get_element_field_names()
|
||
|
|
||
|
def _test_get_element_field_values(self):
|
||
|
field = self._random_element_field_name()
|
||
|
if field is None:
|
||
|
return False
|
||
|
if not self.model.timesteps:
|
||
|
return False
|
||
|
self.model.get_element_field_values(field[1], field[0])
|
||
|
|
||
|
def _test_get_global_variable_names(self):
|
||
|
self.model.get_global_variable_names()
|
||
|
|
||
|
def _test_get_node_field_names(self):
|
||
|
self.model.get_node_field_names()
|
||
|
|
||
|
def _test_get_node_field_values(self):
|
||
|
name = self._random_node_field_name()
|
||
|
if name is None:
|
||
|
return False
|
||
|
if not self.model.timesteps:
|
||
|
return False
|
||
|
self.model.get_node_field_values(name)
|
||
|
|
||
|
def _test_get_node_set_field_names(self):
|
||
|
self.model.get_node_set_field_names()
|
||
|
|
||
|
def _test_get_node_set_ids(self):
|
||
|
self.model.get_node_set_ids()
|
||
|
|
||
|
def _test_get_node_set_members(self):
|
||
|
id_ = self._random_node_set_id()
|
||
|
if id_ is None:
|
||
|
return False
|
||
|
self.model.get_node_set_members(id_)
|
||
|
|
||
|
def _test_get_nodes_in_element_block(self):
|
||
|
ids = self._random_element_block_ids()
|
||
|
if ids is None:
|
||
|
return False
|
||
|
self.model.get_nodes_in_element_block(ids)
|
||
|
|
||
|
def _test_get_nodes_in_side_set(self):
|
||
|
id_ = self._random_side_set_id()
|
||
|
if id_ is None:
|
||
|
return False
|
||
|
self.model.get_nodes_in_side_set(id_)
|
||
|
|
||
|
def _test_get_side_set_ids(self):
|
||
|
self.model.get_side_set_ids()
|
||
|
|
||
|
def _test_get_side_set_field_names(self):
|
||
|
self.model.get_side_set_field_names()
|
||
|
|
||
|
def _test_node_set_field_exists(self):
|
||
|
info = self._random_node_set_field_name()
|
||
|
if info is None:
|
||
|
return False
|
||
|
id_, name = info
|
||
|
assert self.model.node_set_field_exists(name, id_)
|
||
|
|
||
|
def _test_get_node_set_field_values(self):
|
||
|
if not self.model.timesteps:
|
||
|
return False
|
||
|
info = self._random_node_set_field_name()
|
||
|
if info is None:
|
||
|
return False
|
||
|
id_, name = info
|
||
|
self.model.get_node_set_field_values(name, id_)
|
||
|
|
||
|
def _test_get_side_set_field_values(self):
|
||
|
if not self.model.timesteps:
|
||
|
return False
|
||
|
info = self._random_side_set_field_name()
|
||
|
if info is None:
|
||
|
return False
|
||
|
id_, name = info
|
||
|
self.model.get_side_set_field_values(name, id_)
|
||
|
|
||
|
def _test_side_set_field_exists(self):
|
||
|
info = self._random_side_set_field_name()
|
||
|
if info is None:
|
||
|
return False
|
||
|
id_, name = info
|
||
|
assert self.model.side_set_field_exists(name, id_)
|
||
|
|
||
|
def _test_get_timesteps(self):
|
||
|
self.model.get_timesteps()
|
||
|
|
||
|
def _test_global_variable_exists(self):
|
||
|
name = self._random_global_variable_name()
|
||
|
if name is None:
|
||
|
assert not self.model.global_variable_exists("temp")
|
||
|
else:
|
||
|
assert self.model.global_variable_exists(name)
|
||
|
|
||
|
def _test_import_model(self):
|
||
|
if self.remaining_io_tests <= 0:
|
||
|
return False
|
||
|
self.remaining_io_tests -= 1
|
||
|
new_id = random.randint(1, 5)
|
||
|
if self.model.element_block_exists(new_id):
|
||
|
self.model.delete_element_block(new_id)
|
||
|
input_dir = os.path.dirname(__file__)
|
||
|
temp_exo_path = os.path.join(input_dir, "exomerge_unit_test.e")
|
||
|
|
||
|
self.model.import_model(
|
||
|
temp_exo_path,
|
||
|
element_block_ids=new_id,
|
||
|
side_set_ids="none",
|
||
|
node_set_ids="none",
|
||
|
global_variable_names="none",
|
||
|
element_field_names="none",
|
||
|
node_field_names="none",
|
||
|
node_set_field_names="none",
|
||
|
side_set_field_names="none",
|
||
|
timesteps="none",
|
||
|
)
|
||
|
self._truncate_element_blocks()
|
||
|
|
||
|
def _test_node_field_exists(self):
|
||
|
name = self._random_node_field_name()
|
||
|
if name is None:
|
||
|
assert not self.model.node_field_exists("temp")
|
||
|
else:
|
||
|
assert self.model.node_field_exists(name)
|
||
|
|
||
|
def _test_node_set_exists(self):
|
||
|
id_ = self._random_node_set_id()
|
||
|
if id_ is None:
|
||
|
assert not self.model.node_set_exists(0)
|
||
|
else:
|
||
|
assert self.model.node_set_exists(id_)
|
||
|
|
||
|
def _test_process_element_fields(self):
|
||
|
if not self.model.element_blocks:
|
||
|
return False
|
||
|
if not self.model.timesteps:
|
||
|
self.model.create_timestep(0.0)
|
||
|
self.model.delete_element_field("all")
|
||
|
self.model.create_element_field(
|
||
|
self.model._new_element_field_name(), self._random_element_block_id()
|
||
|
)
|
||
|
for name in ["eqps_" + str(x) for x in range(1, 9)]:
|
||
|
self.model.create_element_field(name, "all")
|
||
|
self.model.create_element_field(
|
||
|
self.model._new_element_field_name(), self._random_element_block_id()
|
||
|
)
|
||
|
for name in ["theta_" + str(x) for x in range(1, 10)]:
|
||
|
self.model.create_element_field(name, "all")
|
||
|
self.model.create_element_field(
|
||
|
self.model._new_element_field_name(), self._random_element_block_id()
|
||
|
)
|
||
|
if self.model.get_node_field_names():
|
||
|
self.model.delete_node_field("all")
|
||
|
self.model.process_element_fields()
|
||
|
self._truncate_node_fields()
|
||
|
|
||
|
def _test_rename_element_field(self):
|
||
|
field = self._random_element_field_name()
|
||
|
if field is None:
|
||
|
return False
|
||
|
self.model.rename_element_field(
|
||
|
field[1], self._new_element_field_name(), field[0]
|
||
|
)
|
||
|
|
||
|
def _test_scale_element_blocks(self):
|
||
|
ids = self._random_element_block_ids()
|
||
|
if ids is None:
|
||
|
return False
|
||
|
self.model.unmerge_element_blocks()
|
||
|
self.model.scale_element_blocks(ids, _random_scalar())
|
||
|
|
||
|
def _test_rotate_element_blocks(self):
|
||
|
ids = self._random_element_block_ids()
|
||
|
if ids is None:
|
||
|
return False
|
||
|
self.model.unmerge_element_blocks()
|
||
|
self.model.rotate_element_blocks(ids, [1, 0, 0], 90)
|
||
|
|
||
|
def _test_rotate_geometry(self):
|
||
|
self.model.rotate_geometry([1, 0, 0], 90)
|
||
|
|
||
|
def _test_scale_geometry(self):
|
||
|
self.model.scale_geometry(_random_scalar())
|
||
|
|
||
|
def _test_side_set_exists(self):
|
||
|
id_ = self._random_side_set_id()
|
||
|
if id_ is None:
|
||
|
assert not self.model.side_set_exists(0)
|
||
|
else:
|
||
|
assert self.model.side_set_exists(id_)
|
||
|
|
||
|
def _test_summarize(self):
|
||
|
with OutputSuppression():
|
||
|
self.model.summarize()
|
||
|
|
||
|
def _test_timestep_exists(self):
|
||
|
timestep = _random_element(self.model.timesteps)
|
||
|
if timestep is None:
|
||
|
assert not self.model.timestep_exists(0.0)
|
||
|
else:
|
||
|
assert self.model.timestep_exists(timestep)
|
||
|
|
||
|
def _test_translate_element_blocks(self):
|
||
|
ids = self._random_element_block_ids()
|
||
|
if not ids:
|
||
|
return False
|
||
|
self.model.unmerge_element_blocks()
|
||
|
self.model.translate_element_blocks(ids, _random_vector())
|
||
|
|
||
|
def _test_translate_geometry(self):
|
||
|
self.model.translate_geometry(_random_vector())
|
||
|
|
||
|
def _test_threshold_element_blocks(self):
|
||
|
id_ = self._create_hex8_element_block()
|
||
|
assert self.model.get_element_count(id_) == 2
|
||
|
self.model.calculate_element_centroids(element_block_ids=[id_])
|
||
|
self.model.threshold_element_blocks("centroid_x>1", element_block_ids=[id_])
|
||
|
assert self.model.get_element_count(id_) == 1
|
||
|
|
||
|
def _test_count_degenerate_elements(self):
|
||
|
ids = self._random_element_block_ids()
|
||
|
if not ids:
|
||
|
return False
|
||
|
self.model.count_degenerate_elements(ids)
|
||
|
|
||
|
def _test_delete_duplicate_elements(self):
|
||
|
id_ = self._random_element_block_id()
|
||
|
if id_ is None:
|
||
|
return False
|
||
|
new_id = self._new_element_block_id()
|
||
|
element_count = self.model.get_element_count(id_)
|
||
|
if element_count == 0:
|
||
|
return False
|
||
|
self.model.duplicate_element_block(id_, new_id, duplicate_nodes=False)
|
||
|
self.model.combine_element_blocks([id_, new_id], target_element_block_id=id_)
|
||
|
self.model.delete_duplicate_elements(id_)
|
||
|
assert self.model.get_element_count(id_) <= element_count
|
||
|
|
||
|
def _test_get_closest_node_distance(self):
|
||
|
self.model.get_closest_node_distance()
|
||
|
|
||
|
def _test_get_connectivity(self):
|
||
|
id_ = self._random_element_block_id()
|
||
|
if id_ is None:
|
||
|
return False
|
||
|
self.model.get_connectivity(id_)
|
||
|
|
||
|
def _test_get_element_block_dimension(self):
|
||
|
id_ = self._random_element_block_id()
|
||
|
if id_ is None:
|
||
|
return False
|
||
|
self.model.get_element_block_dimension(id_)
|
||
|
|
||
|
def _test_get_element_block_extents(self):
|
||
|
ids = self._random_element_block_ids()
|
||
|
if not ids:
|
||
|
return False
|
||
|
self.model.get_element_block_extents(ids)
|
||
|
|
||
|
def _test_get_element_block_name(self):
|
||
|
id_ = self._random_element_block_id()
|
||
|
if id_ is None:
|
||
|
return False
|
||
|
self.model.get_element_block_name(id_)
|
||
|
|
||
|
def _test_get_all_element_block_names(self):
|
||
|
self.model.get_all_element_block_names()
|
||
|
|
||
|
def _test_get_element_edge_length_info(self):
|
||
|
ids = self._random_element_block_ids()
|
||
|
if not ids:
|
||
|
return False
|
||
|
self.model.get_element_edge_length_info(ids)
|
||
|
|
||
|
def _test_get_node_set_name(self):
|
||
|
id_ = self._random_node_set_id()
|
||
|
if id_ is None:
|
||
|
return False
|
||
|
self.model.get_node_set_name(id_)
|
||
|
|
||
|
def _test_get_all_node_set_names(self):
|
||
|
self.model.get_all_node_set_names()
|
||
|
|
||
|
def _test_get_side_set_area(self):
|
||
|
id_ = self._random_side_set_id()
|
||
|
if id_ is None:
|
||
|
return False
|
||
|
self.model.get_side_set_area(id_)
|
||
|
|
||
|
def _test_get_side_set_members(self):
|
||
|
id_ = self._random_side_set_id()
|
||
|
if id_ is None:
|
||
|
return False
|
||
|
self.model.get_side_set_members(id_)
|
||
|
|
||
|
def _test_get_side_set_name(self):
|
||
|
id_ = self._random_side_set_id()
|
||
|
if id_ is None:
|
||
|
return False
|
||
|
self.model.get_side_set_name(id_)
|
||
|
|
||
|
def _test_get_all_side_set_names(self):
|
||
|
self.model.get_all_side_set_names()
|
||
|
|
||
|
def _test_build_hex8_cube(self):
|
||
|
new_id = self._new_element_block_id()
|
||
|
self.model.build_hex8_cube(new_id)
|
||
|
|
||
|
def _test_count_disconnected_blocks(self):
|
||
|
ids = self._random_element_block_ids()
|
||
|
if not ids:
|
||
|
return False
|
||
|
self.model.count_disconnected_blocks(ids)
|
||
|
|
||
|
# End of unit test functions.
|
||
|
|
||
|
@staticmethod
|
||
|
def _source_calls_target(source, target):
|
||
|
"""
|
||
|
Return True if the source function calls target somewhere.
|
||
|
|
||
|
"""
|
||
|
source_code = inspect.getsource(source)
|
||
|
return bool(
|
||
|
re.search("[^A-Za-z0-9_]" + target.__name__ + "[ \t\n\r]*\(", source_code)
|
||
|
)
|
||
|
|
||
|
def test(self):
|
||
|
"""
|
||
|
Run the unit tests.
|
||
|
|
||
|
"""
|
||
|
random.seed(0)
|
||
|
exomerge.EXIT_ON_WARNING = True
|
||
|
# get list of all unit tests
|
||
|
tests = inspect.getmembers(self, inspect.ismethod)
|
||
|
unit_tests = []
|
||
|
for test in tests:
|
||
|
if test[0].startswith("_test_"):
|
||
|
unit_tests.append(test)
|
||
|
# get a list of all public functions in exomerge
|
||
|
public_functions = []
|
||
|
|
||
|
for (function, _) in inspect.getmembers(
|
||
|
exomerge.ExodusModel, inspect.isfunction
|
||
|
):
|
||
|
if not function.startswith("_"):
|
||
|
public_functions.append(function)
|
||
|
print(
|
||
|
(
|
||
|
"We found %d unit tests and %d public functions."
|
||
|
% (len(unit_tests), len(public_functions))
|
||
|
)
|
||
|
)
|
||
|
# If a test exists that doesn't match a public function, issue a
|
||
|
# warning message and remove that unit test.
|
||
|
print("\nVerifying each unit test matches a public exomerge function.")
|
||
|
unmatched = []
|
||
|
matched_unit_tests = []
|
||
|
for unit_test in unit_tests:
|
||
|
(test, _) = unit_test
|
||
|
if not test[6:] in public_functions:
|
||
|
unmatched.append(test)
|
||
|
else:
|
||
|
matched_unit_tests.append(unit_test)
|
||
|
if unmatched:
|
||
|
print(
|
||
|
(
|
||
|
"\nWARNING: Found %d unit test(s) without a matching "
|
||
|
"public function\nUnit tests:\n %s"
|
||
|
% (len(unmatched), "\n ".join(unmatched))
|
||
|
)
|
||
|
)
|
||
|
print("")
|
||
|
unit_tests = matched_unit_tests
|
||
|
# If a public function exists without a unit test, issue a warning
|
||
|
# message
|
||
|
print("\nVerifying public function has a matching unit test.")
|
||
|
unmatched = []
|
||
|
unit_test_names = [x[0] for x in unit_tests]
|
||
|
for name in public_functions:
|
||
|
if not "_test_" + name in unit_test_names:
|
||
|
unmatched.append(name)
|
||
|
if unmatched:
|
||
|
print(
|
||
|
(
|
||
|
"\nWARNING: Found %d public functions without a matching "
|
||
|
"unit test\nPublic functions:\n %s"
|
||
|
% (len(unmatched), "\n ".join(unmatched))
|
||
|
)
|
||
|
)
|
||
|
print("")
|
||
|
# make sure unit tests call the appropriate function
|
||
|
# i.e. _test_create_nodes better call create_nodes somewhere
|
||
|
print("\nVerifying each unit test calls the appropriate function.")
|
||
|
bad_unit_tests = []
|
||
|
for name, function in unit_tests:
|
||
|
target = eval("exomerge.ExodusModel." + name[6:])
|
||
|
if not self._source_calls_target(function, target):
|
||
|
bad_unit_tests.append(name)
|
||
|
if bad_unit_tests:
|
||
|
print(
|
||
|
(
|
||
|
"\nWARNING: Found %d unit tests which do not call their "
|
||
|
"corresponding public functions:\n %s"
|
||
|
% (len(bad_unit_tests), "\n ".join(bad_unit_tests))
|
||
|
)
|
||
|
)
|
||
|
print("")
|
||
|
# start off the model
|
||
|
input_dir = os.path.dirname(__file__)
|
||
|
temp_exo_path = os.path.join(input_dir, "exomerge_unit_test.e")
|
||
|
self.model = exomerge.import_model(temp_exo_path)
|
||
|
# run for the given amount of walltime or the number of tests
|
||
|
# is sufficient
|
||
|
start_time = time.time()
|
||
|
end_time = time.time() + self.time_limit
|
||
|
tests = 0
|
||
|
next_tests_to_run = []
|
||
|
passed_tests = set()
|
||
|
while tests < self.max_tests and (
|
||
|
time.time() < end_time or tests < self.min_tests
|
||
|
):
|
||
|
if not next_tests_to_run:
|
||
|
for _ in range(5):
|
||
|
next_tests_to_run.extend(copy.copy(unit_tests))
|
||
|
random.shuffle(next_tests_to_run)
|
||
|
tests += 1
|
||
|
test = next_tests_to_run[0]
|
||
|
del next_tests_to_run[0]
|
||
|
print(("[%d] %s" % (tests, test[0])))
|
||
|
if test[1]() is None:
|
||
|
passed_tests.add(test[0])
|
||
|
if tests % 123 == 0:
|
||
|
self.model._verify(allow_aliased_lists=False)
|
||
|
# if some tests did not successfully run, not that
|
||
|
if len(passed_tests) != len(unit_tests):
|
||
|
untested = []
|
||
|
for (x, _) in unit_tests:
|
||
|
if x not in passed_tests:
|
||
|
untested.append(x)
|
||
|
print(
|
||
|
(
|
||
|
"\nWARNING: Some unit tests were unable to be run:\n "
|
||
|
+ "\n ".join(untested)
|
||
|
)
|
||
|
)
|
||
|
print(("\nRan %d tests in %g seconds." % (tests, time.time() - start_time)))
|
||
|
print("\nSuccess")
|
||
|
|
||
|
|
||
|
# if this module is executed (as opposed to imported), run the tests
|
||
|
if __name__ == "__main__":
|
||
|
if len(sys.argv) > 2:
|
||
|
sys.stderr.write("Invalid syntax.\n")
|
||
|
exit(1)
|
||
|
tester = ExomergeUnitTester()
|
||
|
tester._topology_test()
|
||
|
if len(sys.argv) == 2:
|
||
|
tester.min_tests = int(sys.argv[1])
|
||
|
tester.max_tests = tester.min_tests
|
||
|
tester.test()
|