예제 #1
0
def create_fields_displacement_gradients(coordinates: Field,
                                         reference_coordinates: Field,
                                         mesh: Mesh):
    """
    :return: 1st and 2nd displacement gradients of (coordinates - referenceCoordinates) w.r.t. referenceCoordinates.
    """
    assert (coordinates.getNumberOfComponents()
            == 3) and (reference_coordinates.getNumberOfComponents() == 3)
    fieldmodule = mesh.getFieldmodule()
    dimension = mesh.getDimension()
    with ChangeManager(fieldmodule):
        if dimension == 3:
            u = coordinates - reference_coordinates
            displacement_gradient = fieldmodule.createFieldGradient(
                u, reference_coordinates)
            displacement_gradient2 = fieldmodule.createFieldGradient(
                displacement_gradient, reference_coordinates)
        elif dimension == 2:
            # Note this needs improvement as missing cross terms
            # assume xi directions are approximately normal;
            # effect is to penalise elements where this is not so, which is also desired
            dX_dxi1 = fieldmodule.createFieldDerivative(
                reference_coordinates, 1)
            dX_dxi2 = fieldmodule.createFieldDerivative(
                reference_coordinates, 2)
            dx_dxi1 = fieldmodule.createFieldDerivative(coordinates, 1)
            dx_dxi2 = fieldmodule.createFieldDerivative(coordinates, 2)
            dS1_dxi1 = fieldmodule.createFieldMagnitude(dX_dxi1)
            dS2_dxi2 = fieldmodule.createFieldMagnitude(dX_dxi2)
            du_dS1 = (dx_dxi1 - dX_dxi1) / dS1_dxi1
            du_dS2 = (dx_dxi2 - dX_dxi2) / dS2_dxi2
            displacement_gradient = fieldmodule.createFieldConcatenate(
                [du_dS1, du_dS2])
            # curvature:
            d2u_dSdxi1 = fieldmodule.createFieldDerivative(
                displacement_gradient, 1)
            d2u_dSdxi2 = fieldmodule.createFieldDerivative(
                displacement_gradient, 2)
            displacement_gradient2 = fieldmodule.createFieldConcatenate(
                [d2u_dSdxi1 / dS1_dxi1, d2u_dSdxi2 / dS2_dxi2])
        else:  # dimension == 1
            dX_dxi1 = fieldmodule.createFieldDerivative(
                reference_coordinates, 1)
            dx_dxi1 = fieldmodule.createFieldDerivative(coordinates, 1)
            dS1_dxi1 = fieldmodule.createFieldMagnitude(dX_dxi1)
            displacement_gradient = (dx_dxi1 - dX_dxi1) / dS1_dxi1
            # curvature:
            displacement_gradient2 = fieldmodule.createFieldDerivative(
                displacement_gradient, 1) / dS1_dxi1
    return displacement_gradient, displacement_gradient2
예제 #2
0
def field_is_managed_real_1_to_3_components(field_in: Field):
    """
    Conditional function returning True if the field is real-valued
    with up to 3 components, and is managed.
    """
    return (field_in.getValueType() == Field.VALUE_TYPE_REAL) and \
        (field_in.getNumberOfComponents() <= 3) and field_in.isManaged()
예제 #3
0
def create_fields_transformations(coordinates: Field,
                                  rotation_angles=None,
                                  scale_value=1.0,
                                  translation_offsets=None):
    """
    Create constant fields for rotation, scale and translation containing the supplied
    values, plus the transformed coordinates applying them in the supplied order.
    :param coordinates: The coordinate field to scale, 3 components.
    :param rotation_angles: List of euler angles, length = number of components.
     See create_field_euler_angles_rotation_matrix.
    :param scale_value: Scalar to multiply all components of coordinates.
    :param translation_offsets: List of offsets, length = number of components.
    :return: 4 fields: transformedCoordinates, rotation, scale, translation
    """
    if rotation_angles is None:
        rotation_angles = [0.0, 0.0, 0.0]
    if translation_offsets is None:
        translation_offsets = [0.0, 0.0, 0.0]
    components_count = coordinates.getNumberOfComponents()
    assert (components_count == 3) and (len(rotation_angles) == components_count) and isinstance(scale_value, float) \
        and (len(translation_offsets) == components_count), "createTransformationFields.  Invalid arguments"
    fieldmodule = coordinates.getFieldmodule()
    with ChangeManager(fieldmodule):
        # scale, translate and rotate model, in that order
        rotation = fieldmodule.createFieldConstant(rotation_angles)
        scale = fieldmodule.createFieldConstant(scale_value)
        translation = fieldmodule.createFieldConstant(translation_offsets)
        rotation_matrix = create_field_euler_angles_rotation_matrix(
            fieldmodule, rotation)
        rotated_coordinates = fieldmodule.createFieldMatrixMultiply(
            components_count, rotation_matrix, coordinates)
        transformed_coordinates = rotated_coordinates * scale + translation
        assert transformed_coordinates.isValid()
    return transformed_coordinates, rotation, scale, translation
예제 #4
0
def createFieldsTransformations(coordinates: Field, rotation_angles=None, scale_value=1.0, \
    translation_offsets=None, translation_scale_factor=1.0):
    """
    Create constant fields for rotation, scale and translation containing the supplied
    values, plus the transformed coordinates applying them in the supplied order.
    :param coordinates: The coordinate field to scale, 3 components.
    :param rotation_angles: List of euler angles, length = number of components.
     See create_field_euler_angles_rotation_matrix.
    :param scale_value: Scalar to multiply all components of coordinates.
    :param translation_offsets: List of offsets, length = number of components.
    :param translation_scale_factor: Scaling to multiply translation by so it's magnitude can remain
    close to other parameters for rotation (radians) and scale (assumed close to unit).
    :return: 4 fields: transformedCoordinates, rotation, scale, translation
    """
    if rotation_angles is None:
        rotation_angles = [0.0, 0.0, 0.0]
    if translation_offsets is None:
        translation_offsets = [0.0, 0.0, 0.0]
    components_count = coordinates.getNumberOfComponents()
    assert (components_count == 3) and (len(rotation_angles) == components_count) and isinstance(scale_value, float) \
        and (len(translation_offsets) == components_count), "createFieldsTransformations.  Invalid arguments"
    fieldmodule = coordinates.getFieldmodule()
    with ChangeManager(fieldmodule):
        # Rotate, scale, and translate model, in that order
        rotation = fieldmodule.createFieldConstant(rotation_angles)
        scale = fieldmodule.createFieldConstant(scale_value)
        translation = fieldmodule.createFieldConstant(translation_offsets)
        rotation_matrix = create_field_euler_angles_rotation_matrix(
            fieldmodule, rotation)
        rotated_coordinates = fieldmodule.createFieldMatrixMultiply(
            components_count, rotation_matrix, coordinates)
        transformed_coordinates = rotated_coordinates*scale + (translation if (translation_scale_factor == 1.0) else \
            translation*fieldmodule.createFieldConstant([ translation_scale_factor ]*components_count))
        assert transformed_coordinates.isValid()
    return transformed_coordinates, rotation, scale, translation
예제 #5
0
def field_is_managed_coordinates(field_in: Field):
    """
    Conditional function returning True if the field is Finite Element
    type with 3 components, and is managed.
    """
    return field_in.castFiniteElement().isValid() and (
        field_in.getNumberOfComponents() == 3) and field_in.isManaged()
예제 #6
0
def field_is_managed_coordinates(field_in: Field):
    """
    Conditional function returning True if the field is Finite Element
    type, with coordinate type attribute, up to 3 components, and is managed.
    """
    return (field_in is not None) and field_in.isManaged() and\
        (field_in.getNumberOfComponents() <= 3) and\
        field_in.castFiniteElement().isValid() and field_in.isTypeCoordinate()
예제 #7
0
def evaluate_field_nodeset_mean(field: Field, nodeset: Nodeset):
    """
    :return: Mean of field over nodeset.
    """
    fieldmodule = nodeset.getFieldmodule()
    components_count = field.getNumberOfComponents()
    with ChangeManager(fieldmodule):
        mean_field = fieldmodule.createFieldNodesetMean(field, nodeset)
        fieldcache = fieldmodule.createFieldcache()
        result, mean_values = mean_field.evaluateReal(fieldcache,
                                                      components_count)
        assert result == RESULT_OK
        del mean_field
        del fieldcache
    return mean_values
예제 #8
0
def getNodesetConditionalSize(nodeset: Nodeset, conditionalField: Field):
    """
    :return: Number of objects in nodeset for which conditionalField is True.
    """
    assert conditionalField.getNumberOfComponents() == 1
    fieldmodule = conditionalField.getFieldmodule()
    fieldcache = fieldmodule.createFieldcache()
    nodeiterator = nodeset.createNodeiterator()
    size = 0
    node = nodeiterator.next()
    while node.isValid():
        fieldcache.setNode(node)
        result, value = conditionalField.evaluateReal(fieldcache, 1)
        if value != 0.0:
            size += 1
        node = nodeiterator.next()
    return size
예제 #9
0
def get_node_name_centres(nodeset: Nodeset, coordinates_field: Field,
                          name_field: Field):
    """
    Find mean locations of node coordinate with the same names.
    :param nodeset: Zinc Nodeset or NodesetGroup to search.
    :param coordinates_field: The coordinate field to evaluate.
    :param name_field: The name field to match.
    :return: Dict of names -> coordinates.
    """
    components_count = coordinates_field.getNumberOfComponents()
    fieldmodule = nodeset.getFieldmodule()
    fieldcache = fieldmodule.createFieldcache()
    name_records = {}  # name -> (coordinates, count)
    nodeiter = nodeset.createNodeiterator()
    node = nodeiter.next()
    while node.isValid():
        fieldcache.setNode(node)
        name = name_field.evaluateString(fieldcache)
        coordinates_result, coordinates = coordinates_field.evaluateReal(
            fieldcache, components_count)
        if name and (coordinates_result == RESULT_OK):
            name_record = name_records.get(name)
            if name_record:
                name_centre = name_record[0]
                for c in range(components_count):
                    name_centre[c] += coordinates[c]
                name_record[1] += 1
            else:
                name_records[name] = [coordinates, 1]
        node = nodeiter.next()
    # divide centre coordinates by count
    name_centres = {}
    for name in name_records:
        name_record = name_records[name]
        name_count = name_record[1]
        name_centre = name_record[0]
        if name_count > 1:
            scale = 1.0 / name_count
            for c in range(components_count):
                name_centre[c] *= scale
        name_centres[name] = name_centre
    return name_centres
예제 #10
0
def evaluate_field_nodeset_range(field: Field, nodeset: Nodeset):
    """
    :return: min, max range of field over nodes.
    """
    fieldmodule = nodeset.getFieldmodule()
    components_count = field.getNumberOfComponents()
    with ChangeManager(fieldmodule):
        min_field = fieldmodule.createFieldNodesetMinimum(field, nodeset)
        max_field = fieldmodule.createFieldNodesetMaximum(field, nodeset)
        fieldcache = fieldmodule.createFieldcache()
        result, min_values = min_field.evaluateReal(fieldcache,
                                                    components_count)
        assert result == RESULT_OK
        result, max_values = max_field.evaluateReal(fieldcache,
                                                    components_count)
        assert result == RESULT_OK
        del min_field
        del max_field
        del fieldcache
    return min_values, max_values
예제 #11
0
def evaluate_field_mesh_integral(field: Field, coordinates: Field, mesh: Mesh, number_of_points=4):
    """
    Integrate value of a field over mesh using Gaussian Quadrature.
    :param field: Field to integrate over mesh.
    :param coordinates: Field giving spatial coordinates to integrate over.
    :param mesh: The mesh or mesh group to integrate over.
    :param number_of_points: Number of integration points in each dimension.
    :return: Integral value.
    """
    fieldmodule = mesh.getFieldmodule()
    components_count = field.getNumberOfComponents()
    with ChangeManager(fieldmodule):
        integral = fieldmodule.createFieldMeshIntegral(field, coordinates, mesh)
        integral.setNumbersOfPoints(number_of_points)
        fieldcache = fieldmodule.createFieldcache()
        result, value = integral.evaluateReal(fieldcache, components_count)
        del integral
        del fieldcache
    assert result == RESULT_OK
    return value
예제 #12
0
def create_field_euler_angles_rotation_matrix(fieldmodule: Fieldmodule,
                                              euler_angles: Field) -> Field:
    """
    From OpenCMISS-Zinc graphics_library.cpp, matrix transposed to row major.
    Matrix is product RzRyRx, giving rotation about x, then y, then z with
    positive angles rotating by right hand rule about axis.
    :param fieldmodule: The fieldmodule to create the field in.
    :param euler_angles: 3-component field of angles in radians, components:
    0 = azimuth (about z)
    1 = elevation (about y)
    2 = roll (about x)
    :return: 3x3 rotation matrix field suitable for pre-multiplying vector v
    i.e. v' = Mv
    """
    assert euler_angles.getNumberOfComponents() == 3
    with ChangeManager(fieldmodule):
        azimuth = fieldmodule.createFieldComponent(euler_angles, 1)
        cos_azimuth = fieldmodule.createFieldCos(azimuth)
        sin_azimuth = fieldmodule.createFieldSin(azimuth)
        elevation = fieldmodule.createFieldComponent(euler_angles, 2)
        cos_elevation = fieldmodule.createFieldCos(elevation)
        sin_elevation = fieldmodule.createFieldSin(elevation)
        roll = fieldmodule.createFieldComponent(euler_angles, 3)
        cos_roll = fieldmodule.createFieldCos(roll)
        sin_roll = fieldmodule.createFieldSin(roll)
        minus_one = fieldmodule.createFieldConstant([-1.0])
        cos_azimuth_sin_elevation = cos_azimuth * sin_elevation
        sin_azimuth_sin_elevation = sin_azimuth * sin_elevation
        matrix_components = [
            cos_azimuth * cos_elevation,
            cos_azimuth_sin_elevation * sin_roll - sin_azimuth * cos_roll,
            cos_azimuth_sin_elevation * cos_roll + sin_azimuth * sin_roll,
            sin_azimuth * cos_elevation,
            sin_azimuth_sin_elevation * sin_roll + cos_azimuth * cos_roll,
            sin_azimuth_sin_elevation * cos_roll - cos_azimuth * sin_roll,
            minus_one * sin_elevation, cos_elevation * sin_roll,
            cos_elevation * cos_roll
        ]
        rotation_matrix = fieldmodule.createFieldConcatenate(matrix_components)
    return rotation_matrix
예제 #13
0
def create_field_euler_angles_rotation_matrix(fieldmodule: Fieldmodule, euler_angles: Field) -> Field:
    """
    From OpenCMISS-Zinc graphics_library.cpp, transposed.
    :param fieldmodule:
    :param euler_angles: 3-component field of angles in radians, components:
    1 = azimuth (about z)
    2 = elevation (about rotated y)
    3 = roll (about rotated x)
    :return: 3x3 rotation matrix field suitable for pre-multiplying [x, y, z].
    """
    assert euler_angles.getNumberOfComponents() == 3
    with ChangeManager(fieldmodule):
        azimuth = fieldmodule.createFieldComponent(euler_angles, 1)
        cos_azimuth = fieldmodule.createFieldCos(azimuth)
        sin_azimuth = fieldmodule.createFieldSin(azimuth)
        elevation = fieldmodule.createFieldComponent(euler_angles, 2)
        cos_elevation = fieldmodule.createFieldCos(elevation)
        sin_elevation = fieldmodule.createFieldSin(elevation)
        roll = fieldmodule.createFieldComponent(euler_angles, 3)
        cos_roll = fieldmodule.createFieldCos(roll)
        sin_roll = fieldmodule.createFieldSin(roll)
        minus_one = fieldmodule.createFieldConstant([-1.0])
        cos_azimuth_sin_elevation = cos_azimuth*sin_elevation
        sin_azimuth_sin_elevation = sin_azimuth*sin_elevation
        matrix_components = [
            cos_azimuth*cos_elevation,
            cos_azimuth_sin_elevation*sin_roll - sin_azimuth*cos_roll,
            cos_azimuth_sin_elevation*cos_roll + sin_azimuth*sin_roll,
            sin_azimuth*cos_elevation,
            sin_azimuth_sin_elevation*sin_roll + cos_azimuth*cos_roll,
            sin_azimuth_sin_elevation*cos_roll - cos_azimuth*sin_roll,
            minus_one*sin_elevation,
            cos_elevation*sin_roll,
            cos_elevation*cos_roll]
        rotation_matrix = fieldmodule.createFieldConcatenate(matrix_components)
    return rotation_matrix
예제 #14
0
def transform_coordinates(field: Field,
                          rotation_scale,
                          offset,
                          time=0.0) -> bool:
    """
    Transform finite element field coordinates by matrix and offset, handling nodal derivatives and versions.
    Limited to nodal parameters, rectangular cartesian coordinates
    :param field: the coordinate field to transform
    :param rotation_scale: square transformation matrix 2-D array with as many rows and columns as field components.
    :param offset: coordinates offset.
    :param time: time value.
    :return: True on success, otherwise false.
    """
    ncomp = field.getNumberOfComponents()
    if (ncomp != 2) and (ncomp != 3):
        print(
            'zinc.transformCoordinates: field has invalid number of components'
        )
        return False
    if (len(rotation_scale) != ncomp) or (len(offset) != ncomp):
        print(
            'zinc.transformCoordinates: invalid matrix number of columns or offset size'
        )
        return False
    for matRow in rotation_scale:
        if len(matRow) != ncomp:
            print(
                'zinc.transformCoordinates: invalid matrix number of columns')
            return False
    if field.getCoordinateSystemType(
    ) != Field.COORDINATE_SYSTEM_TYPE_RECTANGULAR_CARTESIAN:
        print('zinc.transformCoordinates: field is not rectangular cartesian')
        return False
    fe_field = field.castFiniteElement()
    if not fe_field.isValid():
        print(
            'zinc.transformCoordinates: field is not finite element field type'
        )
        return False
    success = True
    fm = field.getFieldmodule()
    fm.beginChange()
    cache = fm.createFieldcache()
    cache.setTime(time)
    nodes = fm.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES)
    node_template = nodes.createNodetemplate()
    node_iter = nodes.createNodeiterator()
    node = node_iter.next()
    while node.isValid():
        node_template.defineFieldFromNode(fe_field, node)
        cache.setNode(node)
        for derivative in [
                Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1,
                Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2,
                Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3,
                Node.VALUE_LABEL_D2_DS2DS3, Node.VALUE_LABEL_D3_DS1DS2DS3
        ]:
            versions = node_template.getValueNumberOfVersions(
                fe_field, -1, derivative)
            for v in range(versions):
                result, values = fe_field.getNodeParameters(
                    cache, -1, derivative, v + 1, ncomp)
                if result != RESULT_OK:
                    success = False
                else:
                    new_values = vectorops.matrixvectormult(
                        rotation_scale, values)
                    if derivative == Node.VALUE_LABEL_VALUE:
                        new_values = vectorops.add(new_values, offset)
                    result = fe_field.setNodeParameters(
                        cache, -1, derivative, v + 1, new_values)
                    if result != RESULT_OK:
                        success = False
        node = node_iter.next()
    fm.endChange()
    if not success:
        print('zinc.transformCoordinates: failed to get/set some values')
    return success