Exemple #1
0
def get_dynamic_polygon_raster(dynamic_polygons, rotation_model,
                               reconstruction_time, sampling):

    import tempfile
    import geopandas as gpd
    from rasterio.features import rasterize, Affine

    with tempfile.TemporaryDirectory() as temporary_directory:
        pygplates.resolve_topologies(
            dynamic_polygons, rotation_model,
            '{:s}/masking_temp.shp'.format(temporary_directory),
            reconstruction_time)

        gdf = gpd.read_file(
            '{:s}/masking_temp.shp'.format(temporary_directory))

    dims = (int(180. / sampling) + 1, int(360. / sampling) + 1)
    transform = Affine(sampling, 0.0, -180. - sampling / 2., 0.0, sampling,
                       -90. - sampling / 2.)

    geometry_zval_tuples = [(x.geometry, x.PLATEID1)
                            for i, x in gdf.iterrows()]

    #with rasterio.open(raster_file) as src:
    # iterate over features to get (geometry, id value) pairs
    mask = rasterize(geometry_zval_tuples, transform=transform, out_shape=dims)

    # the first and last columns should match, but may not due to the imposed dateline
    mask[:, 0] = mask[:, -1]

    return mask
Exemple #2
0
def get_topological_boundaries(request):
    """
    http GET request to retrieve reconstructed topological plate polygons

    **usage**
    
    <http-address-to-gws>/topology/plate_boundaries/time=\ *reconstruction_time*\&model=\ *reconstruction_model*
    
    **parameters:**

    *time* : time for reconstruction [default=0]

    *model* : name for reconstruction model [defaults to default model from web service settings]

    **returns:**

    json containing reconstructed plate boundary features
    """

    time = request.GET.get('time', 0)
    model = request.GET.get('model', settings.MODEL_DEFAULT)

    model_dict = get_reconstruction_model_dict(model)

    features = []
    rotation_model = pygplates.RotationModel([
        str('%s/%s/%s' % (settings.MODEL_STORE_DIR, model, rot_file))
        for rot_file in model_dict['RotationFile']
    ])

    # need to handle cases where topologies are in one file, and where they are spread across
    # multiple files
    topology_features = pygplates.FeatureCollection()
    if type(model_dict['PlatePolygons']) is list:
        for file in model_dict['PlatePolygons']:
            fullfile = str('%s/%s/%s' %
                           (settings.MODEL_STORE_DIR, model, file))
            topology_feature = pygplates.FeatureCollection(fullfile)
            topology_features.add(topology_feature)
    else:
        topology_features = pygplates.FeatureCollection(
            str('%s/%s/%s' % (settings.MODEL_STORE_DIR, model,
                              model_dict['PlatePolygons'])))

    resolved_polygons = []
    shared_boundary_sections = []
    pygplates.resolve_topologies(topology_features, rotation_model,
                                 resolved_polygons, float(time),
                                 shared_boundary_sections)

    data = wrap_plate_boundaries(shared_boundary_sections, 0.)
    print('here')
    ret = json.dumps(pretty_floats(data))

    response = HttpResponse(ret, content_type='application/json')
    #TODO:
    response['Access-Control-Allow-Origin'] = '*'
    return response
Exemple #3
0
def write_trees_to_file(input_features, rotation_model, filename, 
                        reconstruction_time_range, time_step=1, 
                        polygon_type='static', root_feature_filename=None):
    
    reconstruction_times = np.arange(reconstruction_time_range[0], reconstruction_time_range[1]+time_step, time_step)

    tree_features = None
    root_centroid_features = []

    for reconstruction_time in reconstruction_times:

        print 'working on time %0.2f Ma' % reconstruction_time

        reconstructed_polygons = []
        if polygon_type is 'topological':
            pygplates.resolve_topologies(input_features, rotation_model, reconstructed_polygons, reconstruction_time)
        
        else:
            pygplates.reconstruct(input_features, rotation_model, reconstructed_polygons, reconstruction_time)

        uniq_plates_from_polygons = get_unique_plate_ids_from_reconstructed_features(reconstructed_polygons)

        reconstruction_tree = rotation_model.get_reconstruction_tree(reconstruction_time)

        chains = get_plate_chains(uniq_plates_from_polygons, reconstruction_tree)

        tree_features = create_hierarchy_features(chains, reconstructed_polygons, tree_features,
                                                  valid_time=(reconstruction_time+time_step/2.,
                                                              reconstruction_time-time_step/2.))
        
        if root_feature_filename is not None:
            
            polygon_centroids = get_polygon_centroids(reconstructed_polygons)
            root_plates = get_root_static_polygon_plate_ids(reconstruction_tree, uniq_plates_from_polygons)
            
            for root_plate in root_plates:
                p0 = polygon_centroids[root_plate]
                feature = pygplates.Feature()
                feature.set_geometry(pygplates.PointOnSphere(p0))
                feature.set_name(str(root_plate))
                feature.set_valid_time(reconstruction_time+time_step/2.,
                                       reconstruction_time-time_step/2.)
                root_centroid_features.append(feature)


    tree_feature_collection = pygplates.FeatureCollection(tree_features)
    tree_feature_collection.write(filename)
    
    if root_feature_filename is not None:
        tree_feature_collection = pygplates.FeatureCollection(root_centroid_features)
        tree_feature_collection.write(root_feature_filename)
Exemple #4
0
def get_topologies_and_plate_id_list(topology_features, rotation_model, time):
    resolved_topologies = []
    pygplates.resolve_topologies(topology_features, rotation_model,
                                 resolved_topologies, time)

    plate_id_list = []
    for topology in resolved_topologies:
        plate_id_list.append(
            topology.get_feature().get_reconstruction_plate_id())

    plate_area_list = []
    for topology in resolved_topologies:
        plate_area_list.append(topology.get_resolved_geometry().get_area())

    return resolved_topologies, plate_id_list, plate_area_list
def get_isochrons_for_ridge_snapshot(topology_features,
                                     rotation_filename,
                                     out_dir,
                                     ridge_time,
                                     time_step,
                                     youngest_seed_time=0,
                                     ridge_sampling=2.):
    print("... Writing seed points along a ridge")
    if not os.path.exists(out_dir):
        os.makedirs(out_dir)

    rotation_model = pygplates.RotationModel(rotation_filename)

    oldest_seed_time = ridge_time

    all_longitudes = []
    all_latitudes = []
    all_ages = []

    # The first step is to generate points along the ridge
    resolved_topologies = []
    shared_boundary_sections = []
    pygplates.resolve_topologies(topology_features, rotation_filename,
                                 resolved_topologies, oldest_seed_time,
                                 shared_boundary_sections)

    # Previous points are on the MOR, current are moved by one time step off MOR.
    curr_points = get_mid_ocean_ridges(shared_boundary_sections,
                                       rotation_model, oldest_seed_time,
                                       time_step, ridge_sampling)

    # Write out the ridge point born at 'ridge_time' but their position at 'ridge_time - time_step'.
    mor_point_features = []
    for curr_point in curr_points:
        feature = pygplates.Feature()
        feature.set_geometry(curr_point)
        feature.set_valid_time(ridge_time, -999)  # delete - time_step
        mor_point_features.append(feature)
    pygplates.FeatureCollection(mor_point_features).write(
        './{:s}/MOR_plus_one_points_{:0.2f}.gmt'.format(out_dir, ridge_time))
    #
    print(
        "... Finished writing seed points along the mid ocean ridge for {:0.2f} Ma"
        .format(ridge_time))
Exemple #6
0
 def gplates_geoms(self, stage_pole_rotation=None, anchor_plate_id=0, fileformat = "gpml"):
     feature_dict = {}
     for age in self.get_times():
         ###########
         #Get topologies
         ###########
         ##########Not sure if the following should be instance attributes (self.resolved_topologies)
         time = age
         resolved_topologies = []
         resolved_topological_sections = []
         ############
         pygplates.resolve_topologies(self.topologies, self.rotation_file, resolved_topologies, time, resolved_topological_sections, anchor_plate_id=0)
         subfeats = []
         ############
         #Get unique boundary types
         ############
         feattypes = []
         for shared_boundary_section in resolved_topological_sections:
             for shared_sub_segment in shared_boundary_section.get_shared_sub_segments():
         # Topological plate polygons and deforming networks have a boundary polygon with an area.
                 feat = shared_sub_segment.get_feature().get_feature_type()
                 featname = feat.get_name()
                 feattypes.append(featname)
         featurelist = list(np.unique((feattypes)))
         ############
         #Update dictionaries, and fill with dummy values
         Age = str(age)
         feature_type_dict = {name: 0 for name in featurelist}
         feature_dict.update({Age : feature_type_dict})
         for feat_name in featurelist:
             subfeats = []
             for shared_boundary_section in resolved_topological_sections:
                 for shared_sub_segment in shared_boundary_section.get_shared_sub_segments():
                 # Topological plate polygons and deforming networks have a boundary polygon with an area.
                     if shared_sub_segment.get_feature().get_feature_type() == pygplates.FeatureType.create_gpml(feat_name):
                         shared_sub_segment_feature = pygplates.Feature()
                         # Replace the cloned geometry property with the sub-segment geometry.
                         shared_sub_segment_feature.set_geometry(shared_sub_segment.get_geometry())
                         #Rotate all objects if required:
                         if stage_pole_rotation:
                             shared_sub_segment_feature.set_geometry(stage_pole_rotation*shared_sub_segment_feature.get_geometry())
                         subfeats.append(shared_sub_segment_feature)
             feature_type_dict.update({feat_name:subfeats})
     return feature_dict
def getRidgeEndPoints(topology_features,rotation_model,time):
# given files to make topological polygons, returns the features of type 'MidOceanRidge'
# and get the first and last point from each one, along with the plate pairs
    
    MorEndPointArrays = []
    MorEndPointGeometries = []
    MorPlatePairs = []
    subduction_boundary_sections = []
    
    # Resolve our topological plate polygons (and deforming networks) to the current 'time'.
    # We generate both the resolved topology boundaries and the boundary sections between them.
    resolved_topologies = []
    shared_boundary_sections = []
    pygplates.resolve_topologies(topology_features, rotation_model, resolved_topologies, time, shared_boundary_sections)
                    
    for shared_boundary_section in shared_boundary_sections:
        if shared_boundary_section.get_feature().get_feature_type() == pygplates.FeatureType.create_gpml('MidOceanRidge'):
                 
            for shared_sub_segment in shared_boundary_section.get_shared_sub_segments():
                
                if len(shared_sub_segment.get_sharing_resolved_topologies())==2:
                    plate_pair = [shared_sub_segment.get_sharing_resolved_topologies()[0].get_feature().get_reconstruction_plate_id(),
                                  shared_sub_segment.get_sharing_resolved_topologies()[1].get_feature().get_reconstruction_plate_id()]
                else:
                    plate_pair = np.array((-1,-1))
                #print 'skipping bad topological segment....'

                tmp = shared_sub_segment.get_geometry()
                
                MorEndPointArrays.append(tmp.to_lat_lon_array())
                MorEndPointGeometries.append(pygplates.PointOnSphere(tmp.get_points()[0]))
                MorEndPointGeometries.append(pygplates.PointOnSphere(tmp.get_points()[-1]))
                MorPlatePairs.append(plate_pair)
                MorPlatePairs.append(plate_pair)
                
        elif shared_boundary_section.get_feature().get_feature_type() == pygplates.FeatureType.create_gpml('SubductionZone'):
                 
            for shared_sub_segment in shared_boundary_section.get_shared_sub_segments():
                
                subduction_boundary_sections.append(shared_sub_segment)
                
                
    return MorEndPointArrays,MorEndPointGeometries,MorPlatePairs,subduction_boundary_sections
def getSubductionBoundarySections(topology_features,rotation_model,time):
# given files to make topological polygons, returns the features of type 'MidOceanRidge'
# and get the first and last point from each one, along with the plate pairs
    
    subduction_boundary_sections = []
    
    # Resolve our topological plate polygons (and deforming networks) to the current 'time'.
    # We generate both the resolved topology boundaries and the boundary sections between them.
    resolved_topologies = []
    shared_boundary_sections = []
    pygplates.resolve_topologies(topology_features, rotation_model, resolved_topologies, time, shared_boundary_sections)
                    
    for shared_boundary_section in shared_boundary_sections:
                
        if shared_boundary_section.get_feature().get_feature_type() == pygplates.FeatureType.create_gpml('SubductionZone'):
                 
            for shared_sub_segment in shared_boundary_section.get_shared_sub_segments():
                
                subduction_boundary_sections.append(shared_sub_segment)
                              
    return subduction_boundary_sections
def resolve_topologies(rotation_model, topological_features,
                       reconstruction_time, output_filename_prefix,
                       output_filename_extension, anchor_plate_id):

    # FIXME: Temporary fix to avoid getting OGR GMT/Shapefile error "Mismatch in field names..." and
    # missing geometries when saving resolved topologies/sections to GMT/Shapefile.
    # It's caused by the OGR writer inside pyglates trying to write out features with different
    # shapefiles attribute field (key) names to the same file. We get around this by removing
    # all shapefile attributes.
    topological_features = pygplates.FeaturesFunctionArgument(
        topological_features).get_features()
    for topological_feature in topological_features:
        topological_feature.remove(
            pygplates.PropertyName.gpml_shapefile_attributes)

    # Resolve our topological plate polygons (and deforming networks) to the current 'reconstruction_time'.
    # We generate both the resolved topology boundaries and the boundary sections between them.
    resolved_topologies = []
    shared_boundary_sections = []
    pygplates.resolve_topologies(topological_features, rotation_model,
                                 resolved_topologies, reconstruction_time,
                                 shared_boundary_sections, anchor_plate_id)

    # We'll create a feature for each boundary polygon feature and each type of
    # resolved topological section feature we find.
    resolved_topology_features = []
    ridge_transform_boundary_section_features = []
    subduction_boundary_section_features = []
    left_subduction_boundary_section_features = []
    right_subduction_boundary_section_features = []

    # Iterate over the resolved topologies.
    for resolved_topology in resolved_topologies:
        resolved_topology_features.append(
            resolved_topology.get_resolved_feature())

    # Iterate over the shared boundary sections.
    for shared_boundary_section in shared_boundary_sections:

        # Get all the geometries of the current boundary section.
        boundary_section_features = [
            shared_sub_segment.get_resolved_feature() for shared_sub_segment in
            shared_boundary_section.get_shared_sub_segments()
        ]

        # Add the feature to the correct list depending on feature type, etc.
        if shared_boundary_section.get_feature().get_feature_type(
        ) == pygplates.FeatureType.create_gpml('SubductionZone'):

            # Put all subduction zones in one collection/file.
            subduction_boundary_section_features.extend(
                boundary_section_features)

            # Also put subduction zones in left/right collection/file.
            polarity_property = shared_boundary_section.get_feature().get(
                pygplates.PropertyName.create_gpml('subductionPolarity'))
            if polarity_property:
                polarity = polarity_property.get_value().get_content()
                if polarity == 'Left':
                    left_subduction_boundary_section_features.extend(
                        boundary_section_features)
                elif polarity == 'Right':
                    right_subduction_boundary_section_features.extend(
                        boundary_section_features)
        else:
            # Put all ridges in one collection/file.
            ridge_transform_boundary_section_features.extend(
                boundary_section_features)

    if resolved_topology_features:
        # Put the features in a feature collection so we can write them to a file.
        resolved_topology_feature_collection = pygplates.FeatureCollection(
            resolved_topology_features)
        resolved_topology_features_filename = '{0}boundary_polygons_{1:0.2f}Ma.{2}'.format(
            output_filename_prefix, reconstruction_time,
            output_filename_extension)
        resolved_topology_feature_collection.write(
            resolved_topology_features_filename)

    if ridge_transform_boundary_section_features:
        # Put the features in a feature collection so we can write them to a file.
        ridge_transform_boundary_section_feature_collection = pygplates.FeatureCollection(
            ridge_transform_boundary_section_features)
        ridge_transform_boundary_section_features_filename = '{0}ridge_transform_boundaries_{1:0.2f}Ma.{2}'.format(
            output_filename_prefix, reconstruction_time,
            output_filename_extension)
        ridge_transform_boundary_section_feature_collection.write(
            ridge_transform_boundary_section_features_filename)

    if subduction_boundary_section_features:
        # Put the features in a feature collection so we can write them to a file.
        subduction_boundary_section_feature_collection = pygplates.FeatureCollection(
            subduction_boundary_section_features)
        subduction_boundary_section_features_filename = '{0}subduction_boundaries_{1:0.2f}Ma.{2}'.format(
            output_filename_prefix, reconstruction_time,
            output_filename_extension)
        subduction_boundary_section_feature_collection.write(
            subduction_boundary_section_features_filename)

    if left_subduction_boundary_section_features:
        # Put the features in a feature collection so we can write them to a file.
        left_subduction_boundary_section_feature_collection = pygplates.FeatureCollection(
            left_subduction_boundary_section_features)
        left_subduction_boundary_section_features_filename = '{0}subduction_boundaries_sL_{1:0.2f}Ma.{2}'.format(
            output_filename_prefix, reconstruction_time,
            output_filename_extension)
        left_subduction_boundary_section_feature_collection.write(
            left_subduction_boundary_section_features_filename)

    if right_subduction_boundary_section_features:
        # Put the features in a feature collection so we can write them to a file.
        right_subduction_boundary_section_feature_collection = pygplates.FeatureCollection(
            right_subduction_boundary_section_features)
        right_subduction_boundary_section_features_filename = '{0}subduction_boundaries_sR_{1:0.2f}Ma.{2}'.format(
            output_filename_prefix, reconstruction_time,
            output_filename_extension)
        right_subduction_boundary_section_feature_collection.write(
            right_subduction_boundary_section_features_filename)
Exemple #10
0
def plot_velocities_and_topologies(pmap,
                                   topology_features,
                                   rotation_model,
                                   time,
                                   delta_time=1,
                                   res=10,
                                   scale=2000,
                                   lon0=0,
                                   clip_path=None,
                                   alpha=0.2):

    Xnodes = np.arange(-180, 180, res)
    Ynodes = np.arange(-90, 90, res)
    Xg, Yg = np.meshgrid(Xnodes, Ynodes)

    velocity_domain_features = make_GPML_velocity_feature(
        Xg.flatten(), Yg.flatten())

    # Call the function we created above to get the velocities
    all_velocities = get_plate_velocities(velocity_domain_features,
                                          topology_features, rotation_model,
                                          time, delta_time, 'vector_comp')

    # The rest of the cell is for plotting, including rendering resolved topological boundaries to the map
    pt_vel_n = []
    pt_vel_e = []
    for vel in all_velocities:
        pt_vel_e.append(vel.get_y())
        pt_vel_n.append(vel.get_x())

    u = np.asarray(pt_vel_e).reshape((Ynodes.shape[0], Xnodes.shape[0]))
    v = np.asarray(pt_vel_n).reshape((Ynodes.shape[0], Xnodes.shape[0]))

    # Resolve our topological plate polygons (and deforming networks) to the current 'time'.
    # We generate both the resolved topology boundaries and the boundary sections between them.
    resolved_topologies = []
    shared_boundary_sections = []
    pygplates.resolve_topologies(topology_features, rotation_model,
                                 resolved_topologies, time,
                                 shared_boundary_sections)

    # create a dateline wrapper object
    wrapper = pygplates.DateLineWrapper(lon0)

    # Iterate over the shared boundary sections.
    for shared_boundary_section in shared_boundary_sections:

        # The shared sub-segments contribute either to the ridges or to the subduction zones.
        if shared_boundary_section.get_feature().get_feature_type(
        ) == pygplates.FeatureType.create_gpml('MidOceanRidge'):
            # Ignore zero length segments - they don't have a direction.
            for shared_sub_segment in shared_boundary_section.get_shared_sub_segments(
            ):
                split_geometry = wrapper.wrap(
                    shared_sub_segment.get_geometry())
                for geometry in split_geometry:
                    X = []
                    Y = []
                    for point in geometry.get_points():
                        X.append(point.get_longitude()), Y.append(
                            point.get_latitude())
                    x, y = pmap(X, Y)
                    pmap.plot(x,
                              y,
                              'darkturquoise',
                              clip_path=clip_path,
                              linewidth=2,
                              alpha=0.5,
                              zorder=1)

        elif shared_boundary_section.get_feature().get_feature_type(
        ) == pygplates.FeatureType.create_gpml('SubductionZone'):
            for shared_sub_segment in shared_boundary_section.get_shared_sub_segments(
            ):
                split_geometry = wrapper.wrap(
                    shared_sub_segment.get_geometry())
                for geometry in split_geometry:
                    X = []
                    Y = []
                    for point in geometry.get_points():
                        X.append(point.get_longitude()), Y.append(
                            point.get_latitude())
                    x, y = pmap(X, Y)
                pmap.plot(x,
                          y,
                          'k',
                          clip_path=clip_path,
                          linewidth=2,
                          alpha=alpha,
                          zorder=1)

        else:  #shared_boundary_section.get_feature().get_feature_type() == pygplates.FeatureType.create_gpml('FractureZone'):
            for shared_sub_segment in shared_boundary_section.get_shared_sub_segments(
            ):
                split_geometry = wrapper.wrap(
                    shared_sub_segment.get_geometry())
                for geometry in split_geometry:
                    X = []
                    Y = []
                    for point in geometry.get_points():
                        X.append(point.get_longitude()), Y.append(
                            point.get_latitude())
                    x, y = pmap(X, Y)
                pmap.plot(x,
                          y,
                          'darkorange',
                          clip_path=clip_path,
                          linewidth=2,
                          alpha=0.6,
                          zorder=1)

    lons, lats = np.meshgrid(Xnodes, Ynodes)
    # compute native x,y coordinates of grid.
    x, y = pmap(lons, lats)
    # define parallels and meridians to draw.

    uproj,vproj,xx,yy = \
    pmap.transform_vector(u,v,Xnodes,Ynodes,54,26,returnxy=True,masked=True)
    # now plot.
    Q = pmap.quiver(xx,
                    yy,
                    uproj,
                    vproj,
                    scale=scale,
                    clip_path=clip_path,
                    alpha=alpha)
def get_initial_ocean_seeds(topology_features,
                            input_rotation_filenames,
                            COBterrane_file,
                            output_directory,
                            time,
                            initial_ocean_mean_spreading_rate,
                            initial_ocean_healpix_sampling,
                            area_threshold,
                            mask_sampling=0.5):
    # Get a set of points at the oldest time for a reconstruction sequence, such that the points
    # populate the ocean basins (defined using the COB Terrane polygons) and are assigned ages assuming
    # a uniform average spreading rate combined with the distance of each point to the nearest
    # MidOceanRidge feature in the resolved plate boundary of the the plate containing the point

    print(
        'Begin creating seed points for initial ocean at reconstruction start time....'
    )

    rotation_model = pygplates.RotationModel(input_rotation_filenames)

    cobter = get_merged_cob_terrane_polygons(COBterrane_file, rotation_model,
                                             time, mask_sampling,
                                             area_threshold)

    ocean_points = pg.rasterise_paleogeography(
        cobter,
        rotation_model,
        time,
        sampling=initial_ocean_healpix_sampling,
        meshtype='healpix',
        masking='Inside')
    #ocean_points = rasterise_polygons(cobter, rotation_model,time,
    #                                  sampling=initial_ocean_healpix_sampling, meshtype='healpix',
    #                                  masking='Inside')

    resolved_topologies = []
    shared_boundary_sections = []
    pygplates.resolve_topologies(topology_features, rotation_model,
                                 resolved_topologies, time,
                                 shared_boundary_sections)

    pX, pY, pZ = pg.find_distance_to_nearest_ridge(resolved_topologies,
                                                   shared_boundary_sections,
                                                   ocean_points)

    # divide spreading rate by 2 to use half spreading rate
    pAge = np.array(pZ) / (initial_ocean_mean_spreading_rate / 2.)

    initial_ocean_point_features = []

    for point in zip(pX, pY, pAge):

        point_feature = pygplates.Feature()
        point_feature.set_geometry(pygplates.PointOnSphere(point[1], point[0]))

        # note that we add 'time' to the age at the time of computation
        # to get the valid time in Ma
        point_feature.set_valid_time(point[2] + time, -1)
        initial_ocean_point_features.append(point_feature)

    pygplates.FeatureCollection(initial_ocean_point_features).write(
        '{:s}/age_from_distance_to_mor_{:0.2f}Ma.gmt'.format(
            output_directory, time))

    print('done')
def resolve_topologies_into_features(
    rotation_features_or_model,
    topology_features,
    time,
    transform_segment_deviation_in_radians=separate_ridge_transform_segments.
    DEFAULT_TRANSFORM_SEGMENT_DEVIATION_RADIANS):
    """
    Resolves topologies at specified time and returns resolved topologies and their boundary sections as subduction zones,
    mid-ocean ridges (ridge/transform) and others (not subduction zones or mid-ocean ridges).
    
    rotation_features_or_model: Rotation model or feature collection(s), or list of features, or filename(s).
    
    topology_features: Topology feature collection(s), or list of features, or filename(s) or any combination of those.
    
    time: Reconstruction time to resolved topologies.
    
    transform_segment_deviation_in_radians: How much a mid-ocean ridge segment can deviate from the stage pole before
                                            it's considered a transform segment (in radians).
    
    Returns: A tuple containing the following lists...
            - resolved topology features (topological plates and networks)
            - ridge and transform boundary sections (resolved features)
            - ridge boundary sections (resolved features)
            - transform boundary sections (resolved features)
            - subduction boundary sections (resolved features)
            - left subduction boundary sections (resolved features)
            - right subduction boundary sections (resolved features)
            - other boundary sections (resolved features) that are not subduction zones or mid-ocean ridges (ridge/transform)
    """
    time = float(time)

    # Turn rotation data into a RotationModel (if not already).
    rotation_model = pygplates.RotationModel(rotation_features_or_model)

    # Turn topology data into a list of features (if not already).
    topology_features = pygplates.FeaturesFunctionArgument(topology_features)

    # Resolve our topological plate polygons (and deforming networks) to the current 'time'.
    # We generate both the resolved topology boundaries and the boundary sections between them.
    resolved_topologies = []
    shared_boundary_sections = []
    pygplates.resolve_topologies(topology_features.get_features(),
                                 rotation_model, resolved_topologies, time,
                                 shared_boundary_sections)

    # We'll create a feature for each boundary polygon feature and each type of
    # resolved topological section feature we find.
    resolved_topology_features = []
    ridge_transform_boundary_section_features = []
    ridge_boundary_section_features = []
    transform_boundary_section_features = []
    subduction_boundary_section_features = []
    left_subduction_boundary_section_features = []
    right_subduction_boundary_section_features = []
    other_boundary_section_features = []

    # Iterate over the resolved topologies.
    for resolved_topology in resolved_topologies:
        resolved_topology_features.append(
            resolved_topology.get_resolved_feature())

    # Iterate over the shared boundary sections.
    for shared_boundary_section in shared_boundary_sections:

        # Get all the geometries of the current boundary section.
        boundary_section_features = [
            shared_sub_segment.get_resolved_feature() for shared_sub_segment in
            shared_boundary_section.get_shared_sub_segments()
        ]

        # Add the feature to the correct list depending on feature type, etc.
        if shared_boundary_section.get_feature().get_feature_type(
        ) == pygplates.FeatureType.gpml_subduction_zone:

            # Put all subduction zones in one collection/file.
            subduction_boundary_section_features.extend(
                boundary_section_features)

            # Also put subduction zones in left/right collection/file.
            polarity_property = shared_boundary_section.get_feature().get(
                pygplates.PropertyName.create_gpml('subductionPolarity'))
            if polarity_property:
                polarity = polarity_property.get_value().get_content()
                if polarity == 'Left':
                    left_subduction_boundary_section_features.extend(
                        boundary_section_features)
                elif polarity == 'Right':
                    right_subduction_boundary_section_features.extend(
                        boundary_section_features)

        elif shared_boundary_section.get_feature().get_feature_type(
        ) == pygplates.FeatureType.gpml_mid_ocean_ridge:
            ridge_transform_boundary_section_features.extend(
                boundary_section_features)

            # Find the stage rotation of the MOR in the frame of reference of its reconstructed geometry at the current 'time'.
            # The stage pole can then be directly geometrically compared to the reconstructed spreading geometry.
            spreading_stage_rotation = separate_ridge_transform_segments.get_stage_rotation_for_reconstructed_geometry(
                shared_boundary_section.get_feature(), rotation_model, time)
            if spreading_stage_rotation:
                boundary_section_geometries = [
                    shared_sub_segment.get_resolved_geometry()
                    for shared_sub_segment in
                    shared_boundary_section.get_shared_sub_segments()
                ]
                for boundary_section_index, boundary_section_feature in enumerate(
                        boundary_section_features):
                    # Split into ridge and transform segments.
                    ridge_and_transform_segment_geometries = separate_ridge_transform_segments.separate_geometry_into_ridges_and_transforms(
                        spreading_stage_rotation,
                        boundary_section_geometries[boundary_section_index],
                        transform_segment_deviation_in_radians)
                    if ridge_and_transform_segment_geometries:
                        ridge_sub_segment_geometries, transform_sub_segment_geometries = ridge_and_transform_segment_geometries

                        if ridge_sub_segment_geometries:
                            ridge_boundary_section_feature = boundary_section_feature.clone(
                            )
                            ridge_boundary_section_feature.set_geometry(
                                ridge_sub_segment_geometries)
                            ridge_boundary_section_features.append(
                                ridge_boundary_section_feature)

                        if transform_sub_segment_geometries:
                            transform_boundary_section_feature = boundary_section_feature.clone(
                            )
                            transform_boundary_section_feature.set_geometry(
                                transform_sub_segment_geometries)
                            transform_boundary_section_features.append(
                                transform_boundary_section_feature)

                    # else skip shared sub segment - it's not a polyline (or polygon).

            # else most likely MOR doesn't have left/right plate IDs or reconstruction/conjugate plate IDs,
            # so don't split into ridge and transform segments.

        else:
            other_boundary_section_features.extend(boundary_section_features)

    return (resolved_topology_features,
            ridge_transform_boundary_section_features,
            ridge_boundary_section_features,
            transform_boundary_section_features,
            subduction_boundary_section_features,
            left_subduction_boundary_section_features,
            right_subduction_boundary_section_features,
            other_boundary_section_features)
Exemple #13
0
 def reconstruct_topologies(self):
     print 'Resolving topologies'
     rotation_model = pygplates.RotationModel(rotation_filenames)
     pygplates.resolve_topologies(topology_filenames, rotation_model,
                                  topology_output_basename + '.shp',
                                  self.reconstruction_time)
Exemple #14
0
def subduction_convergence(
        # Rotation model or feature collection(s), or list of features, or filename(s)...
        rotation_features_or_model,
        # Topology feature collection(s), or list of features, or filename(s) or any combination of those...
        topology_features,
        # Threshold sampling distance along subduction zones (in radians)...
        threshold_sampling_distance_radians,
        time,
        velocity_delta_time=1.0,
        anchor_plate_id=0):

    # Turn rotation data into a RotationModel (if not already).
    rotation_model = pygplates.RotationModel(rotation_features_or_model)

    # Turn topology data into a list of features (if not already).
    topology_features = pygplates.FeaturesFunctionArgument(topology_features)

    # Resolve our topological plate polygons (and deforming networks) to the current 'time'.
    # We generate both the resolved topology boundaries and the boundary sections between them.
    resolved_topologies = []
    shared_boundary_sections = []
    pygplates.resolve_topologies(topology_features.get_features(),
                                 rotation_model, resolved_topologies, time,
                                 shared_boundary_sections, anchor_plate_id)

    # List of tesselated subduction zone shared subsegment points and associated convergence parameters
    # for the current 'time'.
    output_data = []

    # Iterate over the shared boundary sections of all resolved topologies.
    for shared_boundary_section in shared_boundary_sections:

        # Skip sections that are not subduction zones.
        if shared_boundary_section.get_feature().get_feature_type(
        ) != pygplates.FeatureType.gpml_subduction_zone:
            continue

        # Iterate over the shared sub-segments of the current subducting line.
        # These are the parts of the subducting line that actually contribute to topological boundaries.
        for shared_sub_segment in shared_boundary_section.get_shared_sub_segments(
        ):

            # Find the overriding and subducting plates on either side of the shared sub-segment.
            overriding_and_subducting_plates = find_overriding_and_subducting_plates(
                shared_sub_segment, time)
            if not overriding_and_subducting_plates:
                continue
            overriding_plate, subducting_plate, subduction_polarity = overriding_and_subducting_plates
            overriding_plate_id = overriding_plate.get_feature(
            ).get_reconstruction_plate_id()
            subducting_plate_id = subducting_plate.get_feature(
            ).get_reconstruction_plate_id()

            # The plate ID of the subduction zone line (as opposed to the subducting plate).
            #
            # Update: The plate IDs of the subduction zone line and overriding plate can differ
            # even in a non-deforming model due to smaller plates, not modelled by topologies, moving
            # differently than the larger topological plate being modelled - and the subduction zone line
            # having plate IDs of the smaller plates near them. For that reason we use the plate ID
            # of the subduction zone line whenever we can. Since some subduction zone lines can be
            # topological lines, they might actually be deforming (or intended to be deforming) and
            # hence their plate ID is not meaningful or at least we can't be sure whether it will
            # be zero or the overriding plate (or something else). So if the subduction zone line
            # is a topological line then we'll use the overriding plate ID instead.
            #
            if isinstance(shared_boundary_section.get_topological_section(),
                          pygplates.ResolvedTopologicalLine):
                subduction_zone_plate_id = overriding_plate_id
            else:
                subduction_zone_plate_id = shared_sub_segment.get_feature(
                ).get_reconstruction_plate_id()

            # Get the rotation of the subducting plate relative to the overriding plate
            # from 'time + velocity_delta_time' to 'time'.
            convergence_relative_stage_rotation = rotation_model.get_rotation(
                time,
                subducting_plate_id,
                time + velocity_delta_time,
                overriding_plate_id,
                anchor_plate_id=anchor_plate_id)
            #
            # The subduction zones have been reconstructed using the rotation "R(0->t2,A->M)":
            #
            #   reconstructed_geometry = R(0->t2,A->M) * present_day_geometry
            #
            # We can write "R(0->t2,A->M)" in terms of the stage rotation "R(t1->t2,F->M)" as:
            #
            #   R(0->t2,A->M) = R(0->t2,A->F) * R(0->t2,F->M)
            #                 = R(0->t2,A->F) * R(t1->t2,F->M) * R(0->t1,F->M)
            #                 = R(0->t2,A->F) * stage_rotation * R(0->t1,F->M)
            #
            # ...where 't1' is 't+1' and 't2' is 't' (ie, from 't1' to 't2').
            #
            # So to get the *reconstructed* geometry into the stage rotation reference frame
            # we need to rotate it by "inverse[R(0->t2,A->F)]":
            #
            #   reconstructed_geometry = R(0->t2,A->F) * stage_rotation * R(0->t1,F->M) * present_day_geometry
            #   inverse[R(0->t2,A->F)] * reconstructed_geometry = stage_rotation * R(0->t1,F->M) * present_day_geometry
            #
            # Once we've done that we can calculate the velocities of those geometry points
            # using the stage rotation. Then the velocities need to be rotated back from the
            # stage rotation reference frame using the rotation "R(0->t2,A->F)".
            #
            from_stage_frame_relative_to_overriding = rotation_model.get_rotation(
                time, overriding_plate_id, anchor_plate_id=anchor_plate_id)
            to_stage_frame_relative_to_overriding = from_stage_frame_relative_to_overriding.get_inverse(
            )

            # Get the rotation of the subduction zone relative to the anchor plate
            # from 'time + velocity_delta_time' to 'time'.
            #
            # Note: We don't need to convert to and from the stage rotation reference frame
            # like the above convergence because this stage rotation is relative to the anchor plate
            # and so the above to/from stage rotation frame conversion "R(0->t2,A->F)" is the
            # identity rotation since the fixed plate (F) is the anchor plate (A).
            subduction_zone_equivalent_stage_rotation = rotation_model.get_rotation(
                time,
                subduction_zone_plate_id,
                time + velocity_delta_time,
                anchor_plate_id=anchor_plate_id)

            # We need to reverse the subducting_normal vector direction if overriding plate is to
            # the right of the subducting line since great circle arc normal is always to the left.
            if subduction_polarity == 'Left':
                subducting_normal_reversal = 1
            else:
                subducting_normal_reversal = -1

            # Ensure the shared sub-segment is tessellated to within the threshold sampling distance.
            tessellated_shared_sub_segment_polyline = (
                shared_sub_segment.get_resolved_geometry().to_tessellated(
                    threshold_sampling_distance_radians))

            # Iterate over the great circle arcs of the tessellated polyline to get the
            # arc midpoints, lengths and subducting normals.
            # There is an arc between each adjacent pair of points in the polyline.
            arc_midpoints = []
            arc_lengths = []
            subducting_arc_normals = []
            for arc in tessellated_shared_sub_segment_polyline.get_segments():
                if not arc.is_zero_length():
                    arc_midpoints.append(arc.get_arc_point(0.5))
                    arc_lengths.append(arc.get_arc_length())
                    # The normal to the subduction zone in the direction of subduction (towards overriding plate).
                    subducting_arc_normals.append(
                        subducting_normal_reversal *
                        arc.get_great_circle_normal())

            # Shouldn't happen, but just in case the shared sub-segment polyline coincides with a point.
            if not arc_midpoints:
                continue

            # The subducting arc normals relative to North (azimuth).
            # Convert global 3D normal vectors to local (magnitude, azimuth, inclination) tuples (one tuple per point).
            subducting_arc_local_normals = pygplates.LocalCartesian.convert_from_geocentric_to_magnitude_azimuth_inclination(
                arc_midpoints, subducting_arc_normals)

            # Calculate the convergence velocities, and subduction zone velocities relative to
            # overriding plate, at the arc midpoints.
            #
            # Note; We need to convert the reconstructed geometry points into the stage rotation
            # reference frame to calculate velocities and then convert the velocities using the
            # reverse transform as mentioned above.
            arc_midpoints_in_stage_frame_relative_to_overriding = [
                to_stage_frame_relative_to_overriding * arc_midpoint
                for arc_midpoint in arc_midpoints
            ]
            convergence_velocity_vectors_in_stage_frame_relative_to_overriding = pygplates.calculate_velocities(
                arc_midpoints_in_stage_frame_relative_to_overriding,
                convergence_relative_stage_rotation, velocity_delta_time,
                pygplates.VelocityUnits.cms_per_yr)
            convergence_velocity_vectors = [
                from_stage_frame_relative_to_overriding * velocity
                for velocity in
                convergence_velocity_vectors_in_stage_frame_relative_to_overriding
            ]

            # Calculate the absolute velocities at the arc midpoints.
            absolute_velocity_vectors = pygplates.calculate_velocities(
                arc_midpoints, subduction_zone_equivalent_stage_rotation,
                velocity_delta_time, pygplates.VelocityUnits.cms_per_yr)

            for arc_index in range(len(arc_midpoints)):
                arc_midpoint = arc_midpoints[arc_index]
                arc_length = arc_lengths[arc_index]
                subducting_arc_normal = subducting_arc_normals[arc_index]
                subducting_arc_normal_azimuth = subducting_arc_local_normals[
                    arc_index][1]
                lat, lon = arc_midpoint.to_lat_lon()

                # The direction towards which we rotate from the subducting normal in a clockwise fashion.
                clockwise_direction = pygplates.Vector3D.cross(
                    subducting_arc_normal, arc_midpoint.to_xyz())

                # Calculate the convergence rate parameters.
                convergence_velocity_vector = convergence_velocity_vectors[
                    arc_index]
                if convergence_velocity_vector.is_zero_magnitude():
                    convergence_velocity_magnitude = 0
                    convergence_obliquity_degrees = 0
                else:
                    convergence_velocity_magnitude = convergence_velocity_vector.get_magnitude(
                    )
                    convergence_obliquity_degrees = math.degrees(
                        pygplates.Vector3D.angle_between(
                            convergence_velocity_vector,
                            subducting_arc_normal))
                    # Anti-clockwise direction has range (0, -180) instead of (0, 180).
                    if pygplates.Vector3D.dot(convergence_velocity_vector,
                                              clockwise_direction) < 0:
                        convergence_obliquity_degrees = -convergence_obliquity_degrees

                    # See if plates are diverging (moving away from each other).
                    # If plates are diverging (moving away from each other) then make the
                    # velocity magnitude negative to indicate this. This could be inferred from
                    # the obliquity but it seems this is the standard way to output convergence rate.
                    if math.fabs(convergence_obliquity_degrees) > 90:
                        convergence_velocity_magnitude = -convergence_velocity_magnitude

                # Calculate the absolute rate parameters.
                absolute_velocity_vector = absolute_velocity_vectors[arc_index]
                if absolute_velocity_vector.is_zero_magnitude():
                    absolute_velocity_magnitude = 0
                    absolute_obliquity_degrees = 0
                else:
                    absolute_velocity_magnitude = absolute_velocity_vector.get_magnitude(
                    )
                    absolute_obliquity_degrees = math.degrees(
                        pygplates.Vector3D.angle_between(
                            absolute_velocity_vector, subducting_arc_normal))
                    # Anti-clockwise direction has range (0, -180) instead of (0, 180).
                    if pygplates.Vector3D.dot(absolute_velocity_vector,
                                              clockwise_direction) < 0:
                        absolute_obliquity_degrees = -absolute_obliquity_degrees

                    # See if the subduction zone absolute motion is heading in the direction of the
                    # overriding plate. If it is then make the velocity magnitude negative to
                    # indicate this. This could be inferred from the obliquity but it seems this
                    # is the standard way to output convergence rate.
                    #
                    # Note that we are not calculating the motion of the subduction zone
                    # relative to the overriding plate - they are usually attached to each other
                    # and hence wouldn't move relative to each other.
                    if math.fabs(absolute_obliquity_degrees) < 90:
                        absolute_velocity_magnitude = -absolute_velocity_magnitude

                # The data will be output in GMT format (ie, lon first, then lat, etc).
                output_data.append(
                    (lon, lat, convergence_velocity_magnitude,
                     convergence_obliquity_degrees,
                     absolute_velocity_magnitude, absolute_obliquity_degrees,
                     math.degrees(arc_length),
                     math.degrees(subducting_arc_normal_azimuth),
                     subducting_plate_id, overriding_plate_id))

    # Return data sorted since it's easier to compare results (when at least lon/lat is sorted).
    return sorted(output_data)
Exemple #15
0
    def _find_resolved_topologies_containing_points(self):

        current_time = self.get_current_time()

        # Resolve the plate polygons for the current time.
        resolved_topologies = []
        pygplates.resolve_topologies(self.topology_features,
                                     self.rotation_model, resolved_topologies,
                                     current_time)

        if ReconstructByTopologies.use_plate_partitioner:
            # Create a plate partitioner from the resolved polygons.
            plate_partitioner = pygplates.PlatePartitioner(
                resolved_topologies, self.rotation_model)
        else:
            # Some of 'curr_points' will be None so 'curr_valid_points' contains only the valid (not None)
            # points, and 'curr_valid_points_indices' is the same length as 'curr_points' but indexes into
            # 'curr_valid_points' so we can quickly find which point (and hence which resolved topology)
            # in 'curr_valid_points' is associated with the a particular point in 'curr_points'.
            curr_valid_points = []
            curr_valid_points_indices = [None] * self.num_points
            for point_index, curr_point in enumerate(self.curr_points):
                if curr_point is not None:
                    curr_valid_points_indices[point_index] = len(
                        curr_valid_points)
                    curr_valid_points.append(curr_point)
            # For each valid current point find the resolved topology containing it.
            resolved_topologies_containing_curr_valid_points = points_in_polygons.find_polygons(
                curr_valid_points, [
                    resolved_topology.get_resolved_boundary()
                    for resolved_topology in resolved_topologies
                ], resolved_topologies)

        # Iterate over all points.
        for point_index, curr_point in enumerate(self.curr_points):

            if curr_point is None:
                # Current point is not currently active - so skip it.
                self.curr_topology_plate_ids[point_index] = None
                self.curr_resolved_plate_boundaries[point_index] = None
                continue

            # Find the plate id of the polygon that contains 'curr_point'.
            if ReconstructByTopologies.use_plate_partitioner:
                curr_polygon = plate_partitioner.partition_point(curr_point)
            else:
                curr_polygon = resolved_topologies_containing_curr_valid_points[
                    # Index back into 'curr_valid_points' and hence also into
                    # 'resolved_topologies_containing_curr_valid_points'.
                    curr_valid_points_indices[point_index]]
            self.curr_resolved_plate_boundaries[point_index] = curr_polygon

            # If the polygon is None, that means (presumably) that it fell into a crack between
            # topologies. So it will be skipped and thrown away from future iterations.
            if curr_polygon is None:
                self.curr_topology_plate_ids[point_index] = None
                continue

            # Set the plate ID of resolved topology containing current point.
            self.curr_topology_plate_ids[
                point_index] = curr_polygon.get_feature(
                ).get_reconstruction_plate_id()
def query_raster_with_resolved_topologies(raster_filename,
                                          rotation_features_or_model,
                                          time,
                                          query_features,
                                          tessellation_threshold_radians,
                                          search_radius_radians,
                                          smoothing_radius_radians=None,
                                          query_feature_types=None,
                                          anchor_plate_id=0):
    """
    Resolves and tessellates topological features, and queries raster at the resolved tessellated positions.
    
    raster_filename: The filename of the raster/grid file.
    
    rotation_features_or_model: Rotation model or feature collection(s), or list of features, or filename(s).
    
    time: The reconstruction time.
    
    query_features: Topological feature collection(s), or list of features, or filename(s) or any combination of those.
    
    tessellation_threshold_radians: Threshold sampling distance along resolved topological section polylines (in radians).
    
    search_radius_radians: The distance (in radians) from query point to search for non-NaN raster grid values.
                           If none are found for a query point then it will have a query scalar value of NaN.
    
    smoothing_radius_radians: Determines which non-NaN raster grid values (if any) to use in a weighted average for a query point.
                              All points within a radius of 'min_dist + smoothing_radius_radians' of the query point are included
                              (where 'min_dist' is the distance to the closest non-NaN raster grid location).
                              Note that 'smoothing_radius_radians' should be less than 'search_radius_radians'.
                              Default value is None which results in only the closest non-NaN raster grid value being chosen.
    
    query_feature_types: Optional sequence of feature types to filter/accept (defaults to all feature types).
                         Note: The feature types apply to the topological *sections* (eg, subduction zone).
    
    Returns a list with a tuple for each query point containing the following parameters:
    - query point longitude
    - query point latitude
    - query scalar value, is either:
      + sampled from raster (at query point location), or
      + the nearest raster value(s) if query point is in masked (NaN) region of raster (and within search radius), or
      + NaN if there are no non-NaN grid values within search radius.
    - length of tessellated polyline arc segment (in radians) that query point is on.
    """

    # Turn rotation data into a RotationModel (if not already).
    rotation_model = pygplates.RotationModel(rotation_features_or_model)

    # Turn query data into a list of features (if not already).
    query_features = pygplates.FeaturesFunctionArgument(
        query_features).get_features()

    # Note that, for *topological* features, we cannot remove those not matching the allowed feature types
    # because we need to resolve *all* topologies and then filter out the shared topology sections by feature type.

    # Resolve our topological plate polygons (and deforming networks) to the current 'time'.
    # We generate both the resolved topology boundaries and the boundary sections between them.
    query_resolved_topologies = []
    query_shared_boundary_sections = []
    pygplates.resolve_topologies(query_features, rotation_model,
                                 query_resolved_topologies, time,
                                 query_shared_boundary_sections,
                                 anchor_plate_id)

    # Iterate over the shared boundary sections of all resolved topologies.
    query_reconstructed_geometries = []
    for query_shared_boundary_section in query_shared_boundary_sections:
        # Skip sections that are not included in the list of boundary feature types (if any).
        query_feature = query_shared_boundary_section.get_feature()
        if (query_feature_types and query_feature.get_feature_type()
                not in query_feature_types):
            continue

        # Iterate over the shared sub-segments of the current boundary line.
        # These are the parts of the boundary line that actually contribute to topological boundaries.
        for query_shared_sub_segment in query_shared_boundary_section.get_shared_sub_segments(
        ):
            query_reconstructed_geometries.append(
                query_shared_sub_segment.get_resolved_geometry())

    # Tessellate query geometries to get query points and weights.
    query_points, query_point_weights = tessellate_geometries(
        query_reconstructed_geometries, tessellation_threshold_radians)

    # Query the raster at the query points.
    query_point_scalars = query_raster_at_points(raster_filename, query_points,
                                                 search_radius_radians,
                                                 smoothing_radius_radians)

    query_data = []
    for query_point_index in range(len(query_points)):
        query_point_lat, query_point_lon = query_points[
            query_point_index].to_lat_lon()
        query_point_scalar = query_point_scalars[query_point_index]
        query_point_weight = query_point_weights[query_point_index]

        # The data will be output in GMT format (ie, lon first, then lat, etc).
        query_data.append((query_point_lon, query_point_lat,
                           query_point_scalar, query_point_weight))

    return query_data
def subduction_convergence(rotation_features_or_model,
                           topology_features,
                           threshold_sampling_distance_radians,
                           time,
                           velocity_delta_time=1.0,
                           anchor_plate_id=0):
    # Docstring in numpydoc format...
    """Find the convergence and absolute velocities sampled along subduction zones at a particular geological time.
    
    Each sampled point along subduction zones returns the following information:
    
    * subducting convergence (relative to subduction zone) velocity magnitude (in cm/yr)
    * subducting convergence velocity obliquity angle (angle between subduction zone normal vector and convergence velocity vector)
    * subduction zone absolute (relative to anchor plate) velocity magnitude (in cm/yr)
    * subduction zone absolute velocity obliquity angle (angle between subduction zone normal vector and absolute velocity vector)
    * length of arc segment (in degrees) that current point is on
    * subducting arc normal azimuth angle (clockwise starting at North, ie, 0 to 360 degrees) at current point
    * subducting plate ID
    * overriding plate ID
    
    The obliquity angles are in the range (-180 180). The range (0, 180) goes clockwise (when viewed from above the Earth) from the
    subducting normal direction to the velocity vector. The range (0, -180) goes counter-clockwise.
    You can change the range (-180, 180) to the range (0, 360) by adding 360 to negative angles.
    
    Note that the convergence velocity magnitude is negative if the plates are diverging (if convergence obliquity angle
    is greater than 90 or less than -90). And note that the absolute velocity magnitude is negative if the subduction zone (trench)
    is moving towards the overriding plate (if absolute obliquity angle is less than 90 or greater than -90) - note that this
    ignores the kinematics of the subducting plate.
    
    Parameters
    ----------
    rotation_features_or_model : pygplates.RotationModel, or any combination of str, pygplates.FeatureCollection, pygplates.Feature
        The rotation model can be specified as a RotationModel. Or it can be specified as a rotation feature collection,
        or rotation filename, or rotation feature, or sequence of rotation features, or a sequence (eg, list or tuple) of any combination
        of those four types.
    topology_features: any combination of str, pygplates.FeatureCollection, pygplates.Feature
        The topological boundary and network features and the topological section features they reference (regular and topological lines).
        Can be specified as a feature collection, or filename, or feature, or sequence of features, or a sequence (eg, list or tuple)
        of any combination of those four types.
    threshold_sampling_distance_radians: float
        Threshold sampling distance along subduction zones (in radians).
    time: float
        The reconstruction time at which to query subduction convergence.
    velocity_delta_time: float, optional
        The delta time interval used for velocity calculations. Defaults to 1My.
    anchor_plate_id: int, optional
        The anchor plate of the rotation model. Defaults to zero.
    
    Returns
    -------
    list of tuples
        The results for all points sampled along subduction zones.
        The size of the returned list is equal to the number of sampled points.
        Each tuple in the list corresponds to a point and has the following tuple items:
    
    Notes
    -----
    Each point in the output is the midpoint of a great circle arc between two adjacent points in the subduction zone polyline.
    The subduction zone normal vector used in the obliquity calculations is perpendicular to the great circle arc of each point (arc midpoint)
    and pointing towards the overriding plate (rather than away from it).
    
    Each subduction zone is sampled at approximately uniform intervals along its length (specified via a threshold sampling distance).
    The sampling along the entire length of a subduction zone is not exactly uniform. Each segment along a subduction zone is sampled
    such that the samples have a uniform spacing that is less than or equal to the threshold sampling distance. However each segment
    in a subduction zone might have a slightly different spacing distance (since segment lengths are not integer multiples of
    the threshold sampling distance).
    
    The subducting arc normal (at each arc segment mid-point) always points *towards* the overriding plate.
    """

    # Turn rotation data into a RotationModel (if not already).
    rotation_model = pygplates.RotationModel(rotation_features_or_model)

    # Turn topology data into a list of features (if not already).
    topology_features = pygplates.FeaturesFunctionArgument(topology_features)

    # Resolve our topological plate polygons (and deforming networks) to the current 'time'.
    # We generate both the resolved topology boundaries and the boundary sections between them.
    resolved_topologies = []
    shared_boundary_sections = []
    pygplates.resolve_topologies(topology_features.get_features(),
                                 rotation_model, resolved_topologies, time,
                                 shared_boundary_sections, anchor_plate_id)

    # List of tesselated subduction zone shared subsegment points and associated convergence parameters
    # for the current 'time'.
    output_data = []

    # Iterate over the shared boundary sections of all resolved topologies.
    for shared_boundary_section in shared_boundary_sections:

        # Skip sections that are not subduction zones.
        if shared_boundary_section.get_feature().get_feature_type(
        ) != pygplates.FeatureType.gpml_subduction_zone:
            continue

        # Iterate over the shared sub-segments of the current subducting line.
        # These are the parts of the subducting line that actually contribute to topological boundaries.
        for shared_sub_segment in shared_boundary_section.get_shared_sub_segments(
        ):

            # Find the overriding and subducting plates on either side of the shared sub-segment.
            overriding_and_subducting_plates = find_overriding_and_subducting_plates(
                shared_sub_segment, time)
            if not overriding_and_subducting_plates:
                continue
            overriding_plate, subducting_plate, subduction_polarity = overriding_and_subducting_plates
            overriding_plate_id = overriding_plate.get_feature(
            ).get_reconstruction_plate_id()
            subducting_plate_id = subducting_plate.get_feature(
            ).get_reconstruction_plate_id()

            # We need to reverse the subducting_normal vector direction if overriding plate is to
            # the right of the subducting line since great circle arc normal is always to the left.
            if subduction_polarity == 'Left':
                subducting_normal_reversal = 1
            else:
                subducting_normal_reversal = -1

            # The plate ID of the subduction zone line (as opposed to the subducting plate).
            #
            # Update: The plate IDs of the subduction zone line and overriding plate can differ
            # even in a non-deforming model due to smaller plates, not modelled by topologies, moving
            # differently than the larger topological plate being modelled - and the subduction zone line
            # having plate IDs of the smaller plates near them. For that reason we use the plate ID
            # of the subduction zone line whenever we can.
            #
            # If the current shared sub-segment is part of a topological line then we obtain its sub-sub-segments
            # (if we have pyGPlates revision 22 or above). This is because subduction zone lines that are
            # topological lines might actually be deforming (or intended to be deforming) and hence their
            # plate ID is not meaningful or at least we can't be sure whether it will be zero or the
            # overriding plate (or something else). In this case we look at the plate IDs of the
            # sub-sub-segments. However if we have pyGPlates revision 21 or below then we cannot do this,
            # in which case (for a topological line) we'll use the overriding plate ID instead.
            #
            if CAN_HANDLE_TOPOLOGICAL_LINES:
                sub_segments_of_topological_line_sub_segment = shared_sub_segment.get_sub_segments(
                )
                if sub_segments_of_topological_line_sub_segment:
                    # Iterate over the sub-sub-segments associated with the topological line.
                    for sub_sub_segment in sub_segments_of_topological_line_sub_segment:
                        subduction_zone_plate_id = sub_sub_segment.get_feature(
                        ).get_reconstruction_plate_id()
                        sub_segment_geometry = sub_sub_segment.get_resolved_geometry(
                        )
                        _sub_segment_subduction_convergence(
                            output_data, time, sub_segment_geometry,
                            subduction_zone_plate_id, overriding_plate_id,
                            subducting_plate_id, subducting_normal_reversal,
                            threshold_sampling_distance_radians,
                            velocity_delta_time, rotation_model,
                            anchor_plate_id)
                else:  # It's not a topological line...
                    subduction_zone_plate_id = shared_sub_segment.get_feature(
                    ).get_reconstruction_plate_id()
                    sub_segment_geometry = shared_sub_segment.get_resolved_geometry(
                    )
                    _sub_segment_subduction_convergence(
                        output_data, time, sub_segment_geometry,
                        subduction_zone_plate_id, overriding_plate_id,
                        subducting_plate_id, subducting_normal_reversal,
                        threshold_sampling_distance_radians,
                        velocity_delta_time, rotation_model, anchor_plate_id)
            else:  # Cannot handle topological lines (so use overriding plate ID when one is detected)...
                if isinstance(
                        shared_boundary_section.get_topological_section(),
                        pygplates.ResolvedTopologicalLine):
                    subduction_zone_plate_id = overriding_plate_id
                else:
                    subduction_zone_plate_id = shared_sub_segment.get_feature(
                    ).get_reconstruction_plate_id()
                sub_segment_geometry = shared_sub_segment.get_resolved_geometry(
                )
                _sub_segment_subduction_convergence(
                    output_data, time, sub_segment_geometry,
                    subduction_zone_plate_id, overriding_plate_id,
                    subducting_plate_id, subducting_normal_reversal,
                    threshold_sampling_distance_radians, velocity_delta_time,
                    rotation_model, anchor_plate_id)

    # Return data sorted since it's easier to compare results (when at least lon/lat is sorted).
    return sorted(output_data)
def spreading_rates(
        rotation_features_or_model,
        topology_features,
        time,
        threshold_sampling_distance_radians,
        spreading_feature_types=None,
        transform_segment_deviation_in_radians=separate_ridge_transform_segments
    .DEFAULT_TRANSFORM_SEGMENT_DEVIATION_RADIANS,
        velocity_delta_time=1.0,
        anchor_plate_id=0):
    """
    Calculates spreading rate and length of ridge segments of spreading features (mid-ocean ridges) of resolved topologies at specified time.
    
    The transform segments of spreading features are ignored.
    
    Resolves topologies at 'time', tessellates all resolved spreading features to within 'threshold_sampling_distance_radians' radians and
    returns a list of tuples where each tuple represents a tessellated point and contains the following parameters:
    
    - point longitude
    - point latitude
    - spreading velocity magnitude (in cm/yr)
    - length of arc segment (in degrees) that current point is on
    
    
    rotation_features_or_model: Rotation model or feature collection(s), or list of features, or filename(s).
    
    topology_features: Topology feature collection(s), or list of features, or filename(s) or any combination of those.
    
    time: Reconstruction time to resolved topologies.
    
    threshold_sampling_distance_radians: Threshold sampling distance along spreading features (in radians).
    
    spreading_feature_types: Only spreading features with a feature type contained in this list are considered.
                             If None then all spreading features are considered.
    
    transform_segment_deviation_in_radians: How much a segment can deviate from the stage pole before
                                            it's considered a transform segment (in radians).
    
    velocity_delta_time: Delta time interval used to calculate spreading velocity.
    
    Returns: List of the tuples described above.
    """
    time = float(time)

    # Turn rotation data into a RotationModel (if not already).
    rotation_model = pygplates.RotationModel(rotation_features_or_model)

    # Turn topology data into a list of features (if not already).
    topology_features = pygplates.FeaturesFunctionArgument(topology_features)

    # Resolve our topological plate polygons (and deforming networks) to the current 'time'.
    # We generate both the resolved topology boundaries and the boundary sections between them.
    resolved_topologies = []
    shared_boundary_sections = []
    pygplates.resolve_topologies(topology_features.get_features(),
                                 rotation_model, resolved_topologies, time,
                                 shared_boundary_sections, anchor_plate_id)

    # List of tesselated spreading points and associated spreading parameters for the current 'time'.
    output_data = []

    # Iterate over the shared boundary sections of all resolved topologies.
    for shared_boundary_section in shared_boundary_sections:

        spreading_feature = shared_boundary_section.get_feature()

        # Skip sections that are not spreading features (if requested).
        if (spreading_feature_types and spreading_feature.get_feature_type()
                not in spreading_feature_types):
            continue

        # Find the stage rotation of the spreading feature in the frame of reference of its reconstructed geometry at the current 'time'.
        # The stage pole can then be directly geometrically compared to the reconstructed spreading geometry.
        spreading_stage_rotation = separate_ridge_transform_segments.get_stage_rotation_for_reconstructed_geometry(
            spreading_feature, rotation_model, time)
        if not spreading_stage_rotation:
            # Skip current feature - it's not a spreading feature.
            continue

        # Iterate over the shared sub-segments of the current line.
        # These are the parts of the line that actually contribute to topological boundaries.
        for shared_sub_segment in shared_boundary_section.get_shared_sub_segments(
        ):

            # Split into ridge and transform segments.
            ridge_and_transform_segment_geometries = separate_ridge_transform_segments.separate_geometry_into_ridges_and_transforms(
                spreading_stage_rotation,
                shared_sub_segment.get_resolved_geometry(),
                transform_segment_deviation_in_radians)
            if not ridge_and_transform_segment_geometries:
                # Skip shared sub segment - it's not a polyline (or polygon).
                continue

            # Only interested in ridge segments.
            ridge_sub_segment_geometries, _ = ridge_and_transform_segment_geometries

            # Ensure the ridge sub-segments are tessellated to within the threshold sampling distance.
            tessellated_shared_sub_segment_polylines = [
                ridge_sub_segment_geometry.to_tessellated(
                    threshold_sampling_distance_radians)
                for ridge_sub_segment_geometry in ridge_sub_segment_geometries
            ]

            # Iterate over the great circle arcs of the tessellated polylines to get the arc midpoints and lengths.
            # There is an arc between each adjacent pair of points in the polyline.
            arc_midpoints = []
            arc_lengths = []
            for tessellated_shared_sub_segment_polyline in tessellated_shared_sub_segment_polylines:
                for arc in tessellated_shared_sub_segment_polyline.get_segments(
                ):
                    if not arc.is_zero_length():
                        arc_midpoints.append(arc.get_arc_point(0.5))
                        arc_lengths.append(arc.get_arc_length())

            # Shouldn't happen, but just in case ridge sub-segment polylines coincide with points.
            if not arc_midpoints:
                continue

            # Calculate the spreading velocities at the arc midpoints.
            #
            # Note that the stage rotation can be used directly on the reconstructed geometries because
            # it is already in the frame of reference of the reconstructed geometries.
            spreading_velocity_vectors = pygplates.calculate_velocities(
                arc_midpoints, spreading_stage_rotation, velocity_delta_time,
                pygplates.VelocityUnits.cms_per_yr)

            for arc_index in range(len(arc_midpoints)):

                arc_midpoint = arc_midpoints[arc_index]
                arc_length = arc_lengths[arc_index]
                lat, lon = arc_midpoint.to_lat_lon()

                spreading_velocity_magnitude = spreading_velocity_vectors[
                    arc_index].get_magnitude()

                # The data will be output in GMT format (ie, lon first, then lat, etc).
                output_data.append((lon, lat, spreading_velocity_magnitude,
                                    math.degrees(arc_length)))

    return output_data
Exemple #19
0
def velocity_within_topological_boundaries(request):
    """
    http GET request to retrieve plate velocities within topological plate polygons

    **usage**
    
    <http-address-to-gws>/velocity/plate_polygons/time=\ *reconstruction_time*\&model=\ *reconstruction_model*\&velocity_type=\ *velocity_type*\&domain_type=\ *domain_type*
    
    **parameters:**

    *time* : time for reconstruction [default=0]

    *model* : name for reconstruction model [defaults to default model from web service settings]

    *velocity_type* : String specifying the type of velocity representation to return. Can be 'MagAzim' for 
                      magnitude/azimuth, or 'east_north' for velocity components in east and north directions 
                      [default='MagAzim']

    *domain_type* : String specifying the arrangement of domain points on which velocities are calculated. Can
                    be 'longLatGrid' for regular spacing in longitude/latitude, or 'healpix' for an equal area
                    distribution on the sphere [default='longLatGrid']

    **returns:**

    json containing velocity vector features
    """

    time = request.GET.get('time', 0)
    model = request.GET.get('model', settings.MODEL_DEFAULT)
    velocity_type = request.GET.get('velocity_type', 'MagAzim')
    domain_type = request.GET.get('domain_type', 'longLatGrid')

    model_dict = get_reconstruction_model_dict(model)

    rotation_model = pygplates.RotationModel([
        str('%s/%s/%s' % (settings.MODEL_STORE_DIR, model, rot_file))
        for rot_file in model_dict['RotationFile']
    ])

    topology_features = []
    pygplates.resolve_topologies([
        str('%s/%s/%s' % (settings.MODEL_STORE_DIR, model, pp))
        for pp in model_dict['PlatePolygons']
    ],
                                 rotation_model,
                                 topology_features,
                                 reconstruction_time=float(time))
    #print(topology_features)

    if domain_type == 'longLatGrid':
        domain_features = create_gpml_regular_long_lat_mesh(
            1., feature_type='MeshNode')
        lat, lon, vel1, vel2, plate_ids = get_velocities(
            rotation_model,
            topology_features,
            float(time),
            velocity_domain_features=domain_features,
            velocity_type=velocity_type,
            topology_flag=True)

    elif domain_type == 'healpix':
        domain_features = create_gpml_healpix_mesh(32, feature_type='MeshNode')
        lat, lon, vel1, vel2, plate_ids = get_velocities(
            rotation_model,
            topology_features,
            float(time),
            velocity_domain_features=domain_features,
            velocity_type=velocity_type,
            topology_flag=True)

    # prepare the response to be returned
    ret = '{"coordinates":['
    for p in zip(lat, lon, vel1, vel2, plate_ids):
        ret += '[{0:5.2f},{1:5.2f},{2:5.2f},{3:5.2f},{4:5.2f}],'.format(
            p[1], p[0], p[2], p[3], p[4])
    ret = ret[0:-1]
    ret += ']}'

    return HttpResponse(ret, content_type='application/json')