def create_square_element(mesh: Mesh, finite_element_field: Field, node_coordinate_set): """ Create a single square 2-D finite element using the supplied finite element field and sequence of 4 n-D node coordinates. :param mesh: The Zinc Mesh to create elements in. :param finite_element_field: Zinc FieldFiniteElement to interpolate on element. :param node_coordinate_set: Sequence of 4 coordinates each with as many components as finite element field. :return: None """ assert mesh.getDimension() == 2 assert finite_element_field.castFiniteElement().isValid() assert len(node_coordinate_set) == 4 fieldmodule = finite_element_field.getFieldmodule() nodeset = fieldmodule.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES) node_template = nodeset.createNodetemplate() node_template.defineField(finite_element_field) element_template = mesh.createElementtemplate() element_template.setElementShapeType(Element.SHAPE_TYPE_SQUARE) linear_basis = fieldmodule.createElementbasis( 2, Elementbasis.FUNCTION_TYPE_LINEAR_LAGRANGE) eft = mesh.createElementfieldtemplate(linear_basis) element_template.defineField(finite_element_field, -1, eft) field_cache = fieldmodule.createFieldcache() with ChangeManager(fieldmodule): node_identifiers = [] for node_coordinate in node_coordinate_set: node = nodeset.createNode(-1, node_template) node_identifiers.append(node.getIdentifier()) field_cache.setNode(node) finite_element_field.assignReal(field_cache, node_coordinate) element = mesh.createElement(-1, element_template) element.setNodesByIdentifier(eft, node_identifiers) fieldmodule.defineAllFaces()
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
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
def create_field_mesh_integral(coordinates: Field, mesh: Mesh, number_of_points=3): """ Create a field integrating the coordinates to give scalar volume/area/length over the mesh, depending on its dimension. :param coordinates: :param mesh: :param number_of_points: Number of Gauss points. :return: Field giving volume of coordinates field over mesh via Gaussian quadrature. """ fieldmodule = coordinates.getFieldmodule() with ChangeManager(fieldmodule): mesh_integral_field = fieldmodule.createFieldMeshIntegral(fieldmodule.createFieldConstant(1.0), coordinates, mesh) mesh_integral_field.setNumbersOfPoints(number_of_points) return mesh_integral_field
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
def create_field_finite_element_clone(source_field: Field, name: str, managed=False) -> FieldFiniteElement: """ Copy an existing Finite Element Field to a new field of supplied name. Note: does not handle time-varying parameters. New field is not managed by default. :param source_field: Zinc finite element field to copy. :param name: The name of the new field, asserts that no field of that name exists. :param managed: Managed state of field created here. :return: New identically defined field with supplied name. """ assert source_field.castFiniteElement().isValid(), \ "opencmiss.utils.zinc.field.createFieldFiniteElementClone. Not a Zinc finite element field" fieldmodule = source_field.getFieldmodule() field = fieldmodule.findFieldByName(name) assert not field.isValid( ), "opencmiss.utils.zinc.field.createFieldFiniteElementClone. Target field name is in use" with ChangeManager(fieldmodule): # Zinc needs a function to do this efficiently; currently serialise to string, replace field name and reload! source_name = source_field.getName() region = fieldmodule.getRegion() sir = region.createStreaminformationRegion() srm = sir.createStreamresourceMemory() sir.setFieldNames([source_name]) region.write(sir) result, buffer = srm.getBuffer() # small risk of modifying other text here: source_bytes = bytes(") " + source_name + ",", "utf-8") target_bytes = bytes(") " + name + ",", "utf-8") buffer = buffer.replace(source_bytes, target_bytes) sir = region.createStreaminformationRegion() sir.createStreamresourceMemoryBuffer(buffer) result = region.read(sir) assert result == RESULT_OK # note currently must have called endChange before field can be found field = fieldmodule.findFieldByName(name).castFiniteElement() field.setManaged(managed) assert field.isValid() return field
def create_triangle_elements(mesh: Mesh, finite_element_field: Field, element_node_set): """ Create a linear triangular element for every set of 3 local nodes in element_node_set. :param mesh: The Zinc Mesh to create elements in. :param finite_element_field: Zinc FieldFiniteElement to interpolate from nodes. :param element_node_set: Sequence of 3 node identifiers for each element. :return: None """ assert mesh.getDimension() == 2 assert finite_element_field.castFiniteElement().isValid() fieldmodule = finite_element_field.getFieldmodule() element_template = mesh.createElementtemplate() element_template.setElementShapeType(Element.SHAPE_TYPE_TRIANGLE) linear_basis = fieldmodule.createElementbasis( 2, Elementbasis.FUNCTION_TYPE_LINEAR_SIMPLEX) eft = mesh.createElementfieldtemplate(linear_basis) element_template.defineField(finite_element_field, -1, eft) with ChangeManager(fieldmodule): for element_nodes in element_node_set: element = mesh.createElement(-1, element_template) element.setNodesByIdentifier(eft, element_nodes) fieldmodule.defineAllFaces()
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