美文网首页
04_第一个固体潮模型服务接口

04_第一个固体潮模型服务接口

作者: 地学小哥 | 来源:发表于2020-03-19 11:56 被阅读0次

    内容简介:前面两篇文章分别介绍了JKG和Streamlit两种方法,将python代码发布成服务,今天我们体会一下第三种,采用Flask框架来实现。正所谓条条大路通罗马,技术没有什么绝对的好坏,小哥想说的是只要适合那就是最好,怎么选完全看你自己,而多知道一种实现方法,没坏处。

    1、什么是Flask?

    Flask是一个用Python编写的Web应用程序框架。什么是Web应用程序框架?

    Web Application Framework(Web应用程序框架)或简单的Web Framework(Web框架)表示一个库和模块的集合,使Web应用程序开发人员能够编写应用程序,而不必担心协议,线程管理等低级细节。

    在Python生态中,Flask和Django是主流的两种Web解决方案。两者都很有名,社区活跃程度差不多。

    两者可以实现的功能也相似,如果非要对比,那么Flask可以看成是毛坯房,Django是精装修交付。但这不是说Flask不好或简陋,而是Flask给用户更多灵活的配置空间,整个框架也更加轻量级。

    2、固体潮模型计算

    固体潮是啥?那我们首先科普一下,在日、月引潮力的作用下,固体地球产生的周期性形变的现象就叫固体潮。啥地球也能变形,你听的没错,当太阳和月亮相对地球的位置发生改变,万有引力也会发生变化,这个力能让地球表面产生10cm左右量级的变化。

    固体潮不像海潮那样肉眼可见,但是确实是真实存在的,现代化的高精度GPS和重力仪器都可以妥妥地测量到。就拿重力固体潮来说,可以好不夸张地说这是人类迄今为止能预测到的最准确的地球物理现象,没有之一。

    在很多的现代化精密地球科学观测中,固体潮的影响都需要定量扣除,这时候需要计算每个时间和地点上的理论固体潮,然后从仪器观测结果中扣除这部分信号,才能得到要研究的数据对象。

    今天我们以重力固体潮为例,谈谈怎么计算固体潮模型,并发布成一个服务。固体潮模型计算方法有很多,有封闭公式型的,球谐系数方法等,这里面我们不想去深究,总之很成熟了,但是算起来还挺麻烦,代码至少也得有个百十来行吧,公式一堆一堆的,哪如果我们用一个微服务的形式是否可以呢?

    让我们想想,输入/输出应该是什么?

    输入与位置相关,那就是经度/纬度/高度呗;还有时间,那就用北京时间吧;

    输入解决了,那就是输出,输出很简单就是重力固体潮理论值,有个单位用mGal吧

    计算环境

    计算方法有很多,我们推荐使用Geoist工具包,怎么获得和安装,首先弄个开发环境,然后直接从我们的github仓库安装一下,命令如下:

    pip install git+git://github.com/igp-gravity/geoist.git
    

    函数用法

    安装完geoist后,可以直接调用tide模块,计算与太阳相关的重力固体潮gs,与月亮相关的gm和两者之和g。

    from datetime import date, datetime, timedelta
    import geoist.pfm.tide as tide
    gdate = datetime(int(year), int(month), int(day), 
                                     int(hour), int(min), int(sec))
    gdate = gdate - timedelta(hours=8)  #北京为UTC时间+8
    g1 = tide.TideModel()
    gm, gs, g =g1.solve_longman(slat,slon,selev,gdate)
    

    好了,算一个点没问题了,那我要算几天的怎么搞,代码改一下,结果见图1:

    from datetime import datetime
    import geoist.pfm.tide as tide
    g1= tide.TideModel()
    gdate = datetime(2020, 3, 19, 10, 00, 00)
    g1.duration = 5
    g1.increment = 60
    g1.start_time = gdate
    g1.latitude = 45.0
    g1.longitude = 105.0
    g1.altitude = 0.0
    g1.run_model()
    g1.plot()
    
    图1 5天连续固体潮计算结果

    算法请参考:I.M. Longman "Forumlas for Computing the Tidal Accelerations Due to the Moon and the Sun" Journal of Geophysical Research, vol. 64, no. 12, 1959, pp. 2351-2355

    3、Flask封装接口

    那好了计算固体潮没问题了,怎么能编程一个服务大家都能happy呢?好,这就要Flask登场啦,还是先安装:

    pip install Flask
    

    然后编写代码,如下:

    from flask import Flask,jsonify
    
    app  = Flask(__name__)
    
    @app.route('/')
    def hello():
        return 'GEOIST restful API demo! Powered by Flask from Python ecosystem...'
    
    @app.route('/user/<username>')
    def profile(username):
        result = {username : ['{}\'s profile'.format(username)]}
        return jsonify(result)
    
    if __name__ == '__main__':
        app.run(debug = True)
    

    将上述代码保存成一个py文件,例如flaskdemo1.py,然后,在虚拟环境中,运行

    python flaskdemo1.py
    

    运行后,会提示开启了一个本地web服务,这就是一个web的应用啦,如图2:

    图2a flask应用开启窗口
    图2b 封装的接口1
    图2c 封装的接口2

    简单接口这样就成了,但是我们还想再专业一点,别急,用flask下的专用restful插件,没有就再安装一下(这就是毛坯房,想要啥自己装):

    pip install flask_restful
    

    上面的代码改造成下面样式:

    from flask import Flask,jsonify
    from flask_restful import reqparse, abort, Api, Resource
    from datetime import datetime
    import geoist.pfm.tide as tide
    
    app  = Flask(__name__)
    api = Api(app)
    
    @app.route('/')
    def hello():
        return 'GEOIST restful API for Earthtide using longman method...'
    
    class longmantide(Resource):
        def post(self):
            parser = reqparse.RequestParser(bundle_errors=True)
            parser.add_argument('lon', type=float,  required=True, help='经度d.ddd')
            parser.add_argument('lat', type=float,  required=True, help='纬度d.ddd')
            args = parser.parse_args()
            slon = float(args["lon"])
            slat = float(args["lat"])
            t1 = datetime.now()
            g1 = tide.TideModel()
            gm, gs, g = g1.solve_longman(slat,slon,0.0,t1)
            return {'gm': gm, 'gs': gs, 'g':g, 't': str(t1)}
       
    api.add_resource(longmantide, '/tide')
    
    if __name__ == '__main__':
        app.run(debug = True)
    

    注意这次里面用了post接口,而且增加了对request参数的解析(开启了bundle_errors设置,输入错误会提示),POST方式在运行简单浏览器就不行了,这里我们用Postman演示一下提交方法,如图3所示。

    图3 通过POST接口计算指定位置固体潮

    4、生成专业API接口及OpenAPI规范文档

    上面把一个固体潮计算的简单API做好啦,但是我们要给用户用,还需要一个文档说明,最好的方法当然是一起发到web上,要实现这个目标,还要再安装一个flask的插件——文档生成器。

    安装方法:

    pip install flasgger  #http://localhost:5000/apidocs/
    

    flasgger是将代码里面的docstrings发布成swagger UI形式的OpenAPI兼任文档支持模块

    上面例子中的代码变为如下形式:

    from flask import Flask,jsonify
    from flask_restful import reqparse, abort, Api, Resource
    from flasgger import Swagger
    from datetime import datetime
    import geoist.pfm.tide as tide
    
    app  = Flask(__name__)
    api = Api(app)
    swagger = Swagger(app)
    
    @app.route('/')
    def hello():
        '''Earthtide API
        ---
        responses:
          200:
            description: longmentide    
        '''
        return 'GEOIST restful API for Earthtide using longman method...'
    
    class longmantide(Resource):
        def post(self):
            '''计算重力固体潮API接口说明(基于GEOIST开发).
            ---
            parameters:
            - name: lon
              type: float
              required: true
            - name: lat
              type: float
              required: true
            responses:
              200:
                description: longmentide
                schema:
                 id: dict
                 properties:
                   results:
                     type: string
                     description: json string
                     default: {'gm': gm, 'gs': gs, 'g': g, 't': time}
            '''
            parser = reqparse.RequestParser(bundle_errors=True)
            parser.add_argument('lon', type=float,  required=True, help='经度d.ddd')
            parser.add_argument('lat', type=float,  required=True, help='纬度d.ddd')
            args = parser.parse_args()
            slon = float(args["lon"])
            slat = float(args["lat"])
            t1 = datetime.now()
            g1 = tide.TideModel()
            gm, gs, g = g1.solve_longman(slat,slon,0.0,t1)
            return {'gm': gm, 'gs': gs, 'g':g, 't': str(t1)}
        
    api.add_resource(longmantide, '/tide')
    
    if __name__ == '__main__':
        app.run(debug = True)
    

    除了代码层次更加清晰外,然后你再访问apidocs目录下,发现多了一个文档界面

    图3 从docstrings生成API接口文档

    一句话总结:到这里一个基本的RESTful形式API就完成了,如果你有准备好的服务器,可以将python代码连同flask环境打包成一个docker,再通过CD方法部署到k8s服务集群上面,通过云基础设施发布,一套完整的流程走完了,这样一步步循序渐进的来,你是否学会了呢?

    相关文章

      网友评论

          本文标题:04_第一个固体潮模型服务接口

          本文链接:https://www.haomeiwen.com/subject/fisuhhtx.html