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 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()
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 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()
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 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()
def setModelCoordinatesField(self, modelCoordinatesField: Field): finiteElementField = modelCoordinatesField.castFiniteElement() assert finiteElementField.isValid() and ( finiteElementField.getNumberOfComponents() == 3) self._modelCoordinatesField = finiteElementField self._modelCoordinatesFieldName = modelCoordinatesField.getName() modelReferenceCoordinatesFieldName = "reference_" + self._modelCoordinatesField.getName( ) orphanFieldByName(self._fieldmodule, modelReferenceCoordinatesFieldName) self._modelReferenceCoordinatesField = createFieldFiniteElementClone( self._modelCoordinatesField, modelReferenceCoordinatesFieldName) self._updateMarkerCoordinatesField() self._updateMarkerDataLocationCoordinatesField()
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
def assign_field_parameters(target_field: Field, source_field: Field): """ Copy parameters from sourceField to targetField. Currently only works for node parameters. """ field_assignment = target_field.createFieldassignment(source_field) field_assignment.assign()
def setSelectHighlightGroup(self, group: FieldGroup): """ Select and highlight objects in the group. :param group: FieldGroup to select, or None to clear selection. """ fieldmodule = self.getFieldmodule() with ChangeManager(fieldmodule): scene = self.getScene() # can't use SUBELEMENT_HANDLING_MODE_FULL as some groups have been tweaked to omit some faces selectionGroup = get_scene_selection_group( scene, subelementHandlingMode=FieldGroup.SUBELEMENT_HANDLING_MODE_NONE ) if group: if selectionGroup: selectionGroup.clear() else: selectionGroup = create_scene_selection_group( scene, subelementHandlingMode=FieldGroup. SUBELEMENT_HANDLING_MODE_NONE) group_add_group_elements(selectionGroup, group, highest_dimension_only=False) for fieldDomainType in (Field.DOMAIN_TYPE_NODES, Field.DOMAIN_TYPE_DATAPOINTS): group_add_group_nodes( selectionGroup, group, fieldmodule.findNodesetByFieldDomainType( fieldDomainType)) else: if selectionGroup: selectionGroup.clear() scene.setSelectionField(Field())
def isoscalarFieldChanged(self, index): if self._graphics: contours = self._graphics.castContours() if contours.isValid(): isoscalarField = self.ui.isoscalar_field_chooser.getField() if not isoscalarField: isoscalarField = Field() contours.setIsoscalarField(isoscalarField)
def _setupGroupSettingWidgets(self): """ Set up group setting widgets and display values from fitter object. """ self._ui.groupSettings_fieldChooser.setRegion(self._fitter.getRegion()) self._ui.groupSettings_fieldChooser.setNullObjectName("-") self._ui.groupSettings_fieldChooser.setConditional(field_is_managed_group) self._ui.groupSettings_fieldChooser.setField(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 labelFieldChanged(self, index): if self._graphics: pointattributes = self._graphics.getGraphicspointattributes() if pointattributes.isValid(): labelField = self.ui.label_field_chooser.getField() if not labelField: labelField = Field() pointattributes.setLabelField(labelField)
def pointOrientationScaleFieldChanged(self, index): if self._graphics: pointattributes = self._graphics.getGraphicspointattributes() if pointattributes.isValid(): orientationScaleField = self.ui.point_orientation_scale_field_chooser.getField( ) if not orientationScaleField: orientationScaleField = Field() pointattributes.setOrientationScaleField(orientationScaleField)
def lineOrientationScaleFieldChanged(self, index): if self._graphics: lineattributes = self._graphics.getGraphicslineattributes() if lineattributes.isValid(): orientationScaleField = self.ui.line_orientation_scale_field_chooser.getField( ) if not orientationScaleField: orientationScaleField = Field() lineattributes.setOrientationScaleField(orientationScaleField)
def streamVectorFieldChanged(self, index): if self._graphics: streamlines = self._graphics.castStreamlines() if streamlines.isValid(): streamVectorField = self.ui.stream_vector_field_chooser.getField( ) if not streamVectorField: streamVectorField = Field() streamlines.setStreamVectorField(streamVectorField)
def coordinateFieldChanged(self, index): ''' An item was selected at index in coordinate field chooser widget ''' if self._graphics: coordinateField = self.ui.coordinate_field_chooser.getField() if coordinateField: self._graphics.setCoordinateField(coordinateField) else: self._graphics.setCoordinateField(Field())
def clearSelection(self): """ If there is a selection group, clears it and removes it from scene. """ selectionGroup = self.getSelectionGroup() if selectionGroup is not None: selectionGroup.clear() selectionGroup = Field() # NULL scene = self._sceneviewer.getScene() scene.setSelectionField(selectionGroup)
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
def reset(self): self._node = None self._graphics = None self._coordinateField = None self._orientationField = None self._glyphCentre = [0.0, 0.0, 0.0] self._glyphSize = [0.0, 0.0, 0.0] self._glyphScaleFactors = [0.0, 0.0, 0.0] self._variableScaleField = Field() self._nearestElement = None self._elementCoordinateField = None self._createCoordinatesField = None
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_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 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
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 dataFieldChanged(self, index): ''' An item was selected at index in data field chooser widget ''' if self._graphics: dataField = self.ui.data_field_chooser.getField() if dataField: scene = self._graphics.getScene() scene.beginChange() spectrum = self._graphics.getSpectrum() if not spectrum.isValid(): spectrummodule = scene.getSpectrummodule() spectrum = spectrummodule.getDefaultSpectrum() self._graphics.setSpectrum(spectrum) self._graphics.setDataField(dataField) scene.endChange() else: self._graphics.setDataField(Field())
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
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
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
def find_node_with_name(nodeset: Nodeset, name_field: Field, name): """ Get single node in nodeset with supplied name. :param nodeset: Zinc Nodeset or NodesetGroup to search. :param name_field: The name field to match. :param name: The name to match in nameField. :return: Node with name, or None if 0 or multiple nodes with name. """ fieldmodule = nodeset.getFieldmodule() fieldcache = fieldmodule.createFieldcache() nodeiter = nodeset.createNodeiterator() node_with_name = None node = nodeiter.next() while node.isValid(): fieldcache.setNode(node) temp_name = name_field.evaluateString(fieldcache) if temp_name == name: if node_with_name: return None node_with_name = node node = nodeiter.next() return node_with_name