Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

A suggestion to mass_downloader.domain: add distance restriction based on RectangularDomain #3355

Open
1 task done
cuitianyu20 opened this issue Oct 4, 2023 · 4 comments
Labels

Comments

@cuitianyu20
Copy link

Avoid duplicates

  • I searched existing issues

Bug Summary

No distance restrictions.

I can't find any epicentrical distance restrictions based on mass_downloader.domain.RectangularDomain and mass_downloader.restrictions.Restrictions when I use the massdownloader to download seismic data.

For RectangularDomain, obspy just offers the longitude and latitude restrictions. However, if I use the CircularDomain to constrain the domain, I don't need to download total seismic data from all direction (full azimuth). And I don't need to define a new domain based on the Domain which means too complex for me.


Suggestions:

  1. I think it may be better to add a distance restrictions on the mass_downloader.restrictions.Restrictions ( or RectangularDomain?).
  2. When I read the document, I can't directly find any cases about this situation. So I chose a compromise method to achieve the functionality I wanted (as shown in the following code). I just create two different domains and take the common domain to add distance restrictions.
  3. If you think so, do I think it is necessary to add a few words to just remind this compromise method in the obspy doc?
            # Rectangular domain around the epicenter.
            domain = RectangularDomain(minlatitude=sta_range[0], maxlatitude=sta_range[1],
                                    minlongitude=sta_range[2], maxlongitude=sta_range[3])
            if limit_distance:
                # add distance restriction to the Rectangular domain
                domain_restriction = CircularDomain(latitude=event_lat, longitude=event_lon,
                                                    minradius=min_dis, maxradius=max_dis)
        # Waveform data restrictions.
        restrictions = Restrictions(
            # starttime and endtime of waveform data
            starttime=event_time,
            endtime=event_time + wave_len,
            # network and station '*' matches any and can be
            network=array_name,
            station=station_name,
            # If this setting is True, any trace with a gap/overlap will be discarded.
            reject_channels_with_gaps=True,
            # Any trace that is shorter than 95 % of the desired total duration will be discarded.
            minimum_length=0.95,
            sanitize=False,
            minimum_interstation_distance_in_m=0,
            # HH, BH, SH or EH channels. 
            channel_priorities=channel,
            # Location codes
            location_priorities=["*"])

            # Download waveform data
            print('Downloading waveform data, continue...')
            mdl = MassDownloader(debug=False, configure_logging=False) 
            if limit_distance:
                # Add distance restriction based on the Rectangular domain           
                mdl.download((domain and domain_restriction), restrictions, mseed_storage=get_mseed_storage, threads_per_client=3,
                            stationxml_storage="%s/{network}.{station}.xml" % (waveform_station_dir) )

Code to Reproduce

No response

Error Traceback

No response

ObsPy Version?

1.4.0

Operating System?

Ubuntu

Python Version?

3.9.18

Installation Method?

conda

@cuitianyu20 cuitianyu20 added the bug-unconfirmed reported bug that still needs to be confirmed label Oct 4, 2023
@megies
Copy link
Member

megies commented Oct 6, 2023

It should be quite simple to achieve what you need. If I see this right, you can just set up a new subclass to Domain, similar to CircularDomain and RectangularDomain. FDSN servers accept both geometrical restrictions at the same time, so you can just add both together. In principal that's it and you don't even have to implement .is_in_domain() like with the former two the results should be trusted if server implementation is correct. If slightly paranoid about that last part, you could also implement .is_in_domain() to check a combination of both restrictions.

See here

class MyDomain(Domain):

    def __init__(self, minlatitude, maxlatitude, minlongitude,                  
                 maxlongitude, latitude, longitude, minradius,
                 maxradius):                                                 
        self.minlatitude = minlatitude                                          
        self.maxlatitude = maxlatitude                                          
        self.minlongitude = minlongitude                                        
        self.maxlongitude = maxlongitude                                        
        self.latitude = latitude                                                
        self.longitude = longitude                                              
        self.minradius = minradius                                              
        self.maxradius = maxradius                                              
                                                                                
    def get_query_parameters(self):                                             
        return {                                                                
            "minlatitude": self.minlatitude,                                    
            "maxlatitude": self.maxlatitude,                                    
            "minlongitude": self.minlongitude,                                  
            "maxlongitude": self.maxlongitude,                                  
            "latitude": self.latitude,                                          
            "longitude": self.longitude,                                        
            "minradius": self.minradius,                                        
            "maxradius": self.maxradius}                                        

@megies
Copy link
Member

megies commented Oct 6, 2023

You can do the above with your existing installation, if you feel like this would be needed for more people feel free to make a pull request, it would need some new added tests though.

from obspy.clients.fdsn.mass_downloader.domain import Domain

class MyDomain(Domain):
    ...

mydomain = MyDomain(...)

...

mdl.download(mydomain, ...)

@megies megies added .clients.fdsn enhancement feature request and removed bug-unconfirmed reported bug that still needs to be confirmed labels Oct 6, 2023
@cuitianyu20
Copy link
Author

Yeah, I have tested to set up a new subclass to Domain based on class MyDomain(Domain) and also ComDomain = RectangularDomain and CircularDomain. For same setting, I successfully download seismic data based on the latter ComDomain, however, fail to download based on the former MyDomain. I am not sure for the reason and the error message is as follow for all clients (maybe relatived to my computer):
Bad request. If you think your request was valid please contact the developers. HTTP Status code: 400
I also use is_in_domain() to check if a point is in the MyDomain but I get an error raise NotImplementedError.
I am not familiar with the specific usage of this function because it didn't return any information about True/False in the Domain source code.

Anyway, the latter can truely achieve the requirement of combination of two domain.

It should be quite simple to achieve what you need. If I see this right, you can just set up a new subclass to Domain, similar to CircularDomain and RectangularDomain. FDSN servers accept both geometrical restrictions at the same time, so you can just add both together. In principal that's it and you don't even have to implement .is_in_domain() like with the former two the results should be trusted if server implementation is correct. If slightly paranoid about that last part, you could also implement .is_in_domain() to check a combination of both restrictions.

See here

class MyDomain(Domain):

    def __init__(self, minlatitude, maxlatitude, minlongitude,                  
                 maxlongitude, latitude, longitude, minradius,
                 maxradius):                                                 
        self.minlatitude = minlatitude                                          
        self.maxlatitude = maxlatitude                                          
        self.minlongitude = minlongitude                                        
        self.maxlongitude = maxlongitude                                        
        self.latitude = latitude                                                
        self.longitude = longitude                                              
        self.minradius = minradius                                              
        self.maxradius = maxradius                                              
                                                                                
    def get_query_parameters(self):                                             
        return {                                                                
            "minlatitude": self.minlatitude,                                    
            "maxlatitude": self.maxlatitude,                                    
            "minlongitude": self.minlongitude,                                  
            "maxlongitude": self.maxlongitude,                                  
            "latitude": self.latitude,                                          
            "longitude": self.longitude,                                        
            "minradius": self.minradius,                                        
            "maxradius": self.maxradius}                                        

@megies
Copy link
Member

megies commented Oct 9, 2023

however, fail to download based on the former MyDomain. I am not sure for the reason and the error message is as follow for all clients (maybe relatived to my computer

you can set debug=False on the MassDownloader so that it prints the requested URL for the rejected request.

I also use is_in_domain() to check if a point is in the MyDomain but I get an error raise NotImplementedError

The idea is for a custom subclass with more complex geometry logic, you could actually implement that method yourself so that it returns True or False for a given latitude+longitude pair to tell the code if a point should be considered or not. It is not implemented for the existing simple geometries since they can be expressed exactly in the FDSN WS request already, so the geometrical filtering is done on the server side and nothing left to do there.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants