Пример #1
0
def test_model_doc():
    cross_section = FeatureSpec()
    cross_section.add_prop_spec('E', {
        'type': float,
        '>': 0
    },
                                doc="Young's modulus")
    cross_section.add_prop_spec('A', {'type': float, '>': 0}, doc="Area")

    geom = FeatureSpec()
    geom.add_prop_spec('point1', list, doc="Coordinates of point 1")
    geom.add_prop_spec('point2', list, doc="Coordinates of point 2")

    mspec = ModelSpec()
    mspec.add_feature_spec('CrossSection',
                           cross_section,
                           doc="Beam cross section")
    mspec.add_feature_spec('Geom', geom, doc="Beam geometry")

    docs = mspec.get_docs()

    assert docs['CrossSection']['main'] == "Beam cross section"
    assert docs['Geom']['main'] == "Beam geometry"

    assert docs['CrossSection']['sub']['E']['main'] == "Young's modulus"
    assert docs['CrossSection']['sub']['A']['main'] == "Area"
    assert docs['Geom']['sub']['point1']['main'] == "Coordinates of point 1"
    assert docs['Geom']['sub']['point2']['main'] == "Coordinates of point 2"
def test_to_dict_and_documentation():
    """
    Test basic functionality of 'ModelSpec'
    """
    print()

    # ===== Specifications =====

    fspec_beam = FeatureSpec()
    fspec_beam.add_prop_spec('A', {
        'type': int,
        '>': 0
    },
                             doc='Something about property A',
                             max_items=1)
    fspec_beam.add_prop_spec('B', int, doc='Property B is also great')

    fspec_study = FeatureSpec()
    fspec_study.add_prop_spec('static', bool, max_items=1)

    mspec = ModelSpec()
    mspec.add_feature_spec('beam', fspec_beam, doc='A beam carries load')
    mspec.add_feature_spec('study',
                           fspec_study,
                           max_items=1,
                           doc='Specify the type of study to run')

    class Model(mspec.user_class):
        def run(self):
            pass

    beam_model = Model()

    # ===== User logic =====

    beam1 = beam_model.add_feature('beam')
    beam1.set('A', 1)
    beam1.add('B', 2)
    beam1.add('B', 3)

    beam2 = beam_model.add_feature('beam')
    beam2.set('A', 2)
    beam2.add('B', 4)
    beam2.add('B', 6)

    study = beam_model.set_feature('study')
    study.set('static', True)

    # ----- Serialization -----
    model_dict = beam_model.to_dict()
    with open('test.json', 'w') as fp:
        dump_pretty_json(model_dict, fp)

    beam_model = Model().from_dict(model_dict)
    beam1 = beam_model.get('beam')[0]
    assert beam1.get('A') == 1
    assert beam1.get('B') == [2, 3]
Пример #3
0
def test_errors_add_feature_spec():
    """
    Test 'add_feature_spec()' method
    """

    fspec_door = FeatureSpec()
    fspec_door.add_prop_spec('color', str)

    fspec_motor = FeatureSpec()
    fspec_motor.add_prop_spec('type', str)

    mspec_car = ModelSpec()

    # ----- Wrong type: key -----
    with pytest.raises(TypeError):
        mspec_car.add_feature_spec(22, fspec_door)

    # ----- Wrong type: feature_spec -----
    with pytest.raises(TypeError):
        mspec_car.add_feature_spec('door', fspec_door.user_class)

    with pytest.raises(TypeError):
        mspec_car.add_feature_spec('door', fspec_door.user_class())

    # ----- Wrong type: singleton -----
    with pytest.raises(TypeError):
        mspec_car.add_feature_spec('door', fspec_door, singleton='yes')

    # Cannot add property twice...
    mspec_car.add_feature_spec('motor', fspec_motor)
    with pytest.raises(KeyError):
        mspec_car.add_feature_spec('motor', fspec_motor)
Пример #4
0
def test_error_set_feature():
    """

    """
    print()

    fspec = FeatureSpec()
    mspec = ModelSpec()

    fspec.add_prop_spec('a', int, singleton=True)
    fspec.add_prop_spec('b', int, singleton=False)
    mspec.add_feature_spec('A', fspec, singleton=True)

    fspec.add_prop_spec('1', str, singleton=True)
    fspec.add_prop_spec('2', str, singleton=False)
    mspec.add_feature_spec('B', fspec, singleton=False)

    class Model(mspec.user_class):
        def run(self):
            pass

    m = Model()

    # Feature 'A' is non-singleton
    with pytest.raises(RuntimeError):
        m.add_feature('A')
    m.set_feature('A')

    # Feature 'B' is singleton
    with pytest.raises(RuntimeError):
        m.set_feature('B')
    m.add_feature('B')
    m.add_feature('B')
    m.add_feature('B')

    fa = m.get('A')
    fa.set('a', 2)

    fb = m.get('B')
    assert len(fb) == 3

    with pytest.raises(KeyError):
        for _ in m.iter('A'):
            pass

    for _ in m.iter('B'):
        pass
Пример #5
0
def test_basic():
    """
    Test basic functionality of 'ModelSpec'
    """
    print()

    # ===== Specifications =====

    fspec_beam = FeatureSpec()
    fspec_beam.add_prop_spec('A', int)
    fspec_beam.add_prop_spec('B', int, singleton=False)

    fspec_study = FeatureSpec()
    fspec_study.add_prop_spec('static', bool)

    mspec = ModelSpec()
    mspec.add_feature_spec('beam', fspec_beam, singleton=False)
    mspec.add_feature_spec('study', fspec_study, singleton=True)

    class Model(mspec.user_class):
        def run(self):
            pass

    beam_model = Model()

    # ===== User logic =====

    beam1 = beam_model.add_feature('beam')
    beam1.set('A', 1)
    beam1.add('B', 2)
    beam1.add('B', 3)

    beam2 = beam_model.add_feature('beam')
    beam2.set('A', 2)
    beam2.add('B', 4)
    beam2.add('B', 6)

    study = beam_model.set_feature('study')
    study.set('static', True)

    # Beam 1 and 2 have different values for the same property
    assert beam1.get('A') == 1
    assert beam2.get('A') == 2

    # Beams are different, but the parent specification is the same
    assert beam1.uid != beam2.uid
    assert beam1._parent_uid == beam2._parent_uid
Пример #6
0
def test_required_items():
    """
    Check that model can only be run if features and properties are
    well-defined
    """
    print()

    # ===== Specifications =====

    fspec_beam = FeatureSpec()
    fspec_beam.add_prop_spec('A', int, required=1, max_items=1)

    fspec_wing = FeatureSpec()
    fspec_wing.add_prop_spec('B', int, required=3, max_items=3)
    # fspec_wing.add_prop_spec('C', int, required=-1)

    mspec = ModelSpec()
    mspec.add_feature_spec('beam', fspec_beam, required=2)
    mspec.add_feature_spec('wing', fspec_wing, required=1)

    class Model(mspec.user_class):
        def run(self):
            super().run()
    beam_model = Model()

    # ===== User logic =====

    beam1 = beam_model.add_feature('beam')
    beam1.set('A', 2)

    beam2 = beam_model.add_feature('beam')
    beam2.set('A', 2)

    # Feature 'wing' needs to be defined
    with pytest.raises(RuntimeError):
        beam_model.run()

    wing1 = beam_model.add_feature('wing')

    # Property 'B' is needs to be defined
    with pytest.raises(RuntimeError):
        beam_model.run()

    wing1.add('B', 11)
    wing1.add('B', 22)
    wing1.add('B', 33)

    # Cannot add more items of type 'B'
    with pytest.raises(RuntimeError):
        wing1.add('B', 44)

    # Model is now well-defined
    beam_model.run()
Пример #7
0
def test_error_provide_user_class():
    """
    Test method 'user_class'
    """
    print()

    fspec = FeatureSpec()
    fspec.add_prop_spec('a', int, max_items=1)
    fspec.add_prop_spec('b', int)
    Feature = fspec.user_class

    f = Feature()
    f.set('a', 12)
    f.add_many('b', 11, 22, 33)

    with pytest.raises(KeyError):
        f.set('x', 55)

    with pytest.raises(RuntimeError):
        f.add('a', 55)

    with pytest.raises(RuntimeError):
        f.set('b', 55)

    assert f.len('a') == 1
    assert f.len('b') == 3
    assert f.get('a') == 12
    assert f.get('b') == [11, 22, 33]
Пример #8
0
def test_from_dict():
    fspec = FeatureSpec()
    fspec.add_prop_spec('a', int)
    fspec.add_prop_spec('b', str)
    fspec.add_prop_spec('c', {'type': bool})

    Feature = fspec.user_class

    props = {
        'a': [
            42,
        ],
        'b': [
            'snake',
        ],
        'c': [
            True,
        ],
    }

    f = Feature().from_dict(props)

    assert f.get('a') == 42
    assert f.get('b') == 'snake'
    assert f.get('c') is True
Пример #9
0
def test_feature_doc():
    fspec = FeatureSpec()
    fspec.add_prop_spec('E', {'type': float, '>': 0}, doc="Young's modulus")
    fspec.add_prop_spec('A', {'type': float, '>': 0}, doc="Area")
    docs = fspec.get_docs()

    assert len(docs) == 2
    assert docs['E']['main'] == "Young's modulus"
    assert docs['A']['main'] == "Area"

    assert docs['E']['sub'] is None
    assert docs['A']['sub'] is None
Пример #10
0
def test_complex_schema():
    """
    Test variations of more complex property schemas
    """
    print()

    # ===== Specifications =====

    schema_global = {
        'name': {'type': str, 'min_len': 1},
        'mass': {'type': float, '>': 0},
    }

    schema_wing = {
        'id': {'type': str, 'min_len': 3},
        'span': {'type': float, '>': 0},
        'area': {'type': float, '>': 0},
    }

    fspec_aircraft = FeatureSpec()
    fspec_aircraft.add_prop_spec('global', schema_global, max_items=1)
    fspec_aircraft.add_prop_spec('wing', schema_wing)

    Aircraft = fspec_aircraft.user_class
    aircraft = Aircraft()

    # ===== User logic =====

    aircraft.set('global', {'name': 'AD42', 'mass': 50e3})

    aircraft.add('wing', {'id': 'MainWing', 'span': 32.4, 'area': 55.0})
    aircraft.add('wing', {'id': 'HorizTail', 'span': 7.5, 'area': 18.2})

    # Overwrite 'global'
    aircraft.set('global', {'name': 'AD8888', 'mass': 49.9e3})

    # Add method does not apply to 'global'
    with pytest.raises(RuntimeError):
        aircraft.add('global', {'name': 'abc', 'mass': 1.0})

    # Set method does not apply to 'wing'
    with pytest.raises(RuntimeError):
        aircraft.set('wing', {'id': 'abc', 'span': 1.0, 'area': 1.0})

    # Cause schemadict error
    with pytest.raises(TypeError):
        aircraft.set('wing', {'id': 'abc', 'span': 'WRONG_VALUE', 'area': 1.0})
Пример #11
0
                seg.len / self.len)  # TODO: duplicate
            yield Point(p.coord, rel_coord=eta_poly, uid=p.uid)


# ===== Abstract beam element =====

schema_load = {
    'load': S.vector6x1,
    'node': S.pos_int,
    'local_sys': {
        'type': bool
    }
}
schema_mass = {'mass': {'type': S.pos_number}, 'node': S.pos_int}

fspec = FeatureSpec()

for p in Element.PROP_TYPES:
    fspec.add_prop_spec(p, S.pos_number)

fspec.add_prop_spec('up', S.vector3x1)
fspec.add_prop_spec('point_load', schema_load, singleton=False)
fspec.add_prop_spec('dist_load', schema_load, singleton=False)
fspec.add_prop_spec('point_mass', schema_mass, singleton=False)

# =================================


class AbstractEdgeElement(fspec.user_class):
    def __init__(self, p1, p2):
        """
Пример #12
0
            yield Point(p.coord, rel_coord=eta_poly, uid=p.uid)


# ===== Abstract beam element =====

schema_load = {
    'load': S.vector6x1,
    'node': S.pos_int,
    'local_sys': {
        'type': bool
    }
}
schema_distr_load = {'load': S.vector6x1, 'local_sys': {'type': bool}}
schema_mass = {'mass': {'type': S.pos_number}, 'node': S.pos_int}

fspec = FeatureSpec()

for p in Element.PROP_TYPES:
    fspec.add_prop_spec(p, S.pos_number, max_items=1)

fspec.add_prop_spec('up', S.vector3x1, max_items=1)
fspec.add_prop_spec('point_load', schema_load)
fspec.add_prop_spec('distr_load', schema_load)
fspec.add_prop_spec('dist_load', schema_load)
fspec.add_prop_spec('point_mass', schema_mass)

# =================================


class AbstractEdgeElement(fspec.user_class):
    def __init__(self, p1, p2):
Пример #13
0
def test_basic():
    """
    Test basic functionality of 'FeatureSpec'
    """
    print()

    # ===== Specifications =====

    fspec = FeatureSpec()
    fspec.add_prop_spec('A', int, max_items=1)
    fspec.add_prop_spec('B', int, max_items=1)
    fspec.add_prop_spec('C', int)
    fspec.add_prop_spec('D', {'type': int, '>': 0}, max_items=1)

    # Check that schemas cannot be defined twice
    with pytest.raises(KeyError):
        fspec.add_prop_spec('D', str)

    Feature = fspec.user_class
    f = Feature()

    # ===== User logic =====

    # ----- set() method -----
    f.set('A', 5)
    f.set('B', 8)
    f.set('B', 9)

    # Check the added values
    assert f.get('A') == 5
    assert f.get('B') == 9

    # Property 'B' can only have one entry
    assert f.len('B') == 1

    # Check that keys which are not allowed cannot be set
    with pytest.raises(KeyError):
        f.set("PROPERTY_DOES_NOT_EXIST", 10)

    # Value for 'D' can only be positive (see specification)
    f.set('D', 4)
    with pytest.raises(ValueError):
        f.set('D', -4)

    # ----- add() method -----
    f.add('C', 11)
    f.add('C', 22)
    f.add('C', 33)

    # Property 'C' has three entries
    assert f.len('C') == 3

    # Check that keys which are not allowed cannot be added
    with pytest.raises(KeyError):
        f.add("PROPERTY_DOES_NOT_EXIST", 10)

    # Check the added values
    assert f.get('C') == [11, 22, 33]

    exp_items = [11, 22, 33]
    for i, item in enumerate(f.iter('C')):
        assert item == exp_items[i]

    # Cannot iterate over unique property
    with pytest.raises(KeyError):
        for _ in f.iter('A'):
            pass
Пример #14
0
# TODO:
# - acceleration state (define on beam level, or 'global'?)

# =================
# ===== MODEL =====
# =================
mspec = ModelSpec()

tmp_doc = "The *{X}* feature is optional and allows to define sets of constant \
           {X} properties. When defining the properties for a specific beam \
           (or parts of it), you may refer to a {X} set using its UID. You may \
           define as many sets as you like."

# ===== Material =====
fspec = FeatureSpec()
fspec.add_prop_spec('E',
                    S.pos_number,
                    required=True,
                    doc="Young's modulus [N/m²]")
fspec.add_prop_spec('G',
                    S.pos_number,
                    required=True,
                    doc="Shear modulus [N/m²]")
fspec.add_prop_spec('rho', S.pos_number, required=True, doc="Density [kg/m³]")
mspec.add_feature_spec(
    'material',
    fspec,
    singleton=False,
    required=False,
    doc=tmp_doc.format(X='material'),
Пример #15
0
#!/usr/bin/env python3
# -*- coding: utf-8 -*-m

# _model.py
from mframework import FeatureSpec, ModelSpec

from ._run import run_model

# Here, we only have numerical user input. We only allow positive floats.
SCHEMA_POS_FLOAT = {'type': float, '>': 0}

# ===== MODEL =====
mspec = ModelSpec()

# Create the first feature 'ambiance'
fspec = FeatureSpec()
fspec.add_prop_spec('g', SCHEMA_POS_FLOAT, doc='Gravitational acceleration')
fspec.add_prop_spec('a', SCHEMA_POS_FLOAT, doc='Speed of sound')
mspec.add_feature_spec('ambiance', fspec, doc='Ambient flight conditions')

# Feature 'aerodynamics'
fspec = FeatureSpec()
fspec.add_prop_spec('CL', SCHEMA_POS_FLOAT, doc='Cruise lift coefficient')
fspec.add_prop_spec('CD', SCHEMA_POS_FLOAT, doc='Cruise drag coefficient')
fspec.add_prop_spec('Mach', SCHEMA_POS_FLOAT, doc='Cruise Mach number')
mspec.add_feature_spec('aerodynamics', fspec, doc='Aerodynamic properties')

# Feature 'propulsion'
fspec = FeatureSpec()
fspec.add_prop_spec('cT',
                    SCHEMA_POS_FLOAT,
Пример #16
0
def test_from_dict():
    fspec1 = FeatureSpec()
    fspec1.add_prop_spec('a', int)
    fspec1.add_prop_spec('b', str)
    fspec1.add_prop_spec('c', {'type': bool})

    fspec2 = FeatureSpec()
    fspec2.add_prop_spec('one', int)
    fspec2.add_prop_spec('two', str)
    fspec2.add_prop_spec('three', {'type': bool})

    mspec = ModelSpec()
    mspec.add_feature_spec('A', fspec1)
    mspec.add_feature_spec('B', fspec2)

    class Model(mspec.user_class):
        def run(self):
            pass

    props1 = {
        'a': [
            42,
        ],
        'b': [
            'snake',
        ],
        'c': [
            True,
        ],
    }

    props2 = {
        'one': [
            43,
        ],
        'two': [
            'Snake',
        ],
        'three': [
            False,
        ],
    }

    model_dict = {
        'A': [
            props1,
        ],
        'B': [
            props2,
        ],
    }

    m = Model().from_dict(model_dict)
    m_fa = m.get('A')
    m_fb = m.get('B')

    assert m_fa.get('a') == 42
    assert m_fa.get('b') == 'snake'
    assert m_fa.get('c') is True

    assert m_fb.get('one') == 43
    assert m_fb.get('two') == 'Snake'
    assert m_fb.get('three') is False
Пример #17
0
def test_error_add_property_spec():
    """
    Test method 'add_prop_spec()'
    """

    fspec = FeatureSpec()

    # ----- Wrong type: key -----
    with pytest.raises(TypeError):
        fspec.add_prop_spec(44, int)

    # ----- Wrong type: schema -----
    class MySpecialNumber:
        pass
    with pytest.raises(TypeError):
        fspec.add_prop_spec('number', MySpecialNumber)

    # ----- Wrong type: max_items -----
    with pytest.raises(TypeError):
        fspec.add_prop_spec('number', int, max_items='yes')

    # ----- Wrong type: required -----
    with pytest.raises(TypeError):
        fspec.add_prop_spec('number', int, required='yes', max_items=1)

    # Cannot add property twice...
    fspec.add_prop_spec('color', str)
    with pytest.raises(KeyError):
        fspec.add_prop_spec('color', str)
Пример #18
0
SchemadictValidators.register_type(np.ndarray)
SchemadictValidators.register_type(sparse.csr_matrix)
SchemadictValidators[str]['is_dir'] = is_dir

# =================
# ===== MODEL =====
# =================
mspec = ModelSpec()

tmp_doc = "The *{X}* feature is optional and allows to define sets of constant \
           {X} properties. When defining the properties for a specific beam \
           (or parts of it), you may refer to a {X} set using its UID. You may \
           define as many sets as you like."

# ===== Material =====
fspec = FeatureSpec()
fspec.add_prop_spec('E',
                    S.pos_number,
                    max_items=1,
                    doc="Young's modulus [N/m²]")
fspec.add_prop_spec('G', S.pos_number, max_items=1, doc="Shear modulus [N/m²]")
fspec.add_prop_spec('rho', S.pos_number, max_items=1, doc="Density [kg/m³]")
mspec.add_feature_spec(
    'material',
    fspec,
    required=0,
    doc=tmp_doc.format(X='material'),
    uid_required=True,
)

# ===== Cross-section =====