产汇流模拟及代码实现(洪水山洪模拟应用)

        产汇流模拟是水文学、地理学和环境科学等领域中的一种重要研究方法,主要用于模拟降水转化为地表径流的过程。这个过程涉及到降雨量的分布、土壤类型、地形地貌、植被覆盖、土地利用等因素对水分渗透、储存和流失的影响。

具体来说,产汇流模拟主要包括以下几个步骤:

1. 数据准备:收集和处理所需的输入数据,包括DEM(数字高程模型)以获取地形信息,气象站观测的降雨数据,土壤类型及参数,植被覆盖度,土地利用类型等。

2. 流域划分与特征提取:根据DEM进行子流域划分,并计算各个子流域的相关水文特性,如面积、平均坡度、流向、蓄水能力等。

3. 选择或构建模型:选择适合特定流域特性的产汇流模型,例如基于物理过程的连续方程模型(如SAC-SMA、SWAT、HEC-HMS等),或者基于统计经验关系的模型(如Green-Ampt、Philip infiltration模型等)。

4. 模型参数率定与校验:使用历史观测数据对模型参数进行率定,通过对比模拟结果与实测径流数据,优化模型参数,提高模型预测精度。

5. 模拟运行与分析:输入未来气候变化情景下的降雨数据,运行模型进行产汇流模拟,进而分析不同情境下径流变化规律,为水资源管理、洪水预警、水利工程设计以及生态环境保护等方面提供决策支持。

6. 成果展示与应用:将模拟结果以图表、地图等形式直观展示,供决策者和科研人员参考和分析。在实际应用中,产汇流模拟能够帮助我们更好地理解并预测水资源的时空动态变化,为合理开发、管理和保护水资源提供科学依据。

产汇流模拟软件成果展示

应用场景

山洪模拟:

产汇流基础数据

产汇流模拟关键代码实现

entities:[],
isRLayerPanel: true,
url: '/static/localRain.json',
dataPath: '',
options:{
  id:'chl',
  name:'产汇流模拟',
  isShow:false
},
location: {
  "destination":{"x":-1289406.2535686514,"y":5146053.096414656,"z":3551139.094344541},"orientation":{"heading":6.240559515291201,"pitch":-1.4942952503663536,"roll":0.0021848124262540125},
  duration: 2
}
//计算经纬度步进长度
_calcStep:function(){
  let isextent = (this.extent.length!=0);
  let calcExtent = isextent?this.extent:this.initExtent;
  let calcSpeed = this.speedRate;
  this.calc_speedRate = [(calcExtent[1]-calcExtent[0])/calcSpeed,(calcExtent[3]-calcExtent[2])/calcSpeed];
}
animate: function () {
  let self = this,
    field = self.windField;
  let nextLng = null,
    nextLat = null,
    uv = null;
  self.particles.forEach(function (particle) {
    if (particle.age == null || particle.age <= 0) {
      self.randomParticle(particle);
    }
    if (particle.age > 0) {
      let x = particle.x,
        y = particle.y,
        tlng = particle.tlng,
        tlat = particle.tlat;
      let gridpos = self._togrid(tlng,tlat);
      let tx = gridpos[0];
      let ty = gridpos[1];

      if (!self.isInExtent(tlng,tlat)) {
        particle.age = 0;
      } else {
        uv = field.getIn(tx, ty);
        nextLng = tlng +  self.calc_speedRate[0] * uv[0];
        nextLat = tlat -  self.calc_speedRate[1] * uv[1];
        particle.lng = tlng;
        particle.lat = tlat;
        particle.x = tx;
        particle.y = ty;
        particle.tlng = nextLng;
        particle.tlat = nextLat;
        particle.age--;
      }
    }
  });
  if (self.particles.length <= 0) this.removeLines();
  self._drawLines();
},
//粒子是否在地图范围内
isInExtent:function(lng,lat){
  let calcExtent = this.initExtent;
  if((lng>=calcExtent[0] && lng<=calcExtent[1]) && (lat>=calcExtent[2] && lat<=calcExtent[3])) return true;
  return false;
},
_resize:function(width,height){
  this.canvasWidth = width;
  this.canvasHeight = height;
}
removeLines: function () {
  window.cancelAnimationFrame(this.animateFrame);
  this.isdistory = true;
  this.canvas.width = 1;
  document.getElementById('content').removeChild(this.canvas);
},
//根据粒子当前所处的位置(棋盘网格位置),计算经纬度,在根据经纬度返回屏幕坐标
_tomap: function (lng,lat,particle) {
  let ct3 = Cartesian3.fromDegrees(lng,lat,0);
  // 判断当前点是否在地球可见端
  let isVisible = new EllipsoidalOccluder(Ellipsoid.WGS84, this.viewer.camera.position).isPointVisible(ct3);
  let pos = SceneTransforms.wgs84ToWindowCoordinates(this.viewer.scene, ct3);
  if(!isVisible){
    particle.age = 0;
  }
  // console.log(pos);
  return pos?[pos.x,pos.y]:null;
},
//根据经纬度,算出棋盘格位置
_togrid: function (lng,lat) {
  let field = this.windField;
  let x = (lng-this.initExtent[0])/(this.initExtent[1]-this.initExtent[0])*(field.cols-1);
  let y = (this.initExtent[3]-lat)/(this.initExtent[3]-this.initExtent[2])*(field.rows-1);
  return [x,y];
},
_drawLines: function () {
  let self = this;
  let particles = this.particles;
  this.canvasContext.lineWidth = self.lineWidth;
  //后绘制的图形和前绘制的图形如果发生遮挡的话,只显示后绘制的图形跟前一个绘制的图形重合的前绘制的图形部分,示例:https://www.w3school.com.cn/tiy/t.asp?f=html5_canvas_globalcompop_all
  this.canvasContext.globalCompositeOperation = "destination-in";
  this.canvasContext.fillRect(0,0,this.canvasWidth,this.canvasHeight);
  this.canvasContext.globalCompositeOperation = "lighter";//重叠部分的颜色会被重新计算
  this.canvasContext.globalAlpha = 0.9;
  this.canvasContext.beginPath();
  this.canvasContext.strokeStyle = this.color;
  particles.forEach(function (particle) {
    let movetopos = self._tomap(particle.lng, particle.lat,particle);
    let linetopos = self._tomap(particle.tlng, particle.tlat,particle);
    // let movetopos = self._tomap(particle.tlng, particle.tlat,particle);
    // let linetopos = self._tomap(particle.lng, particle.lat,particle);
    // console.log(movetopos,linetopos);
    if(movetopos!=null && linetopos!=null){
      self.canvasContext.moveTo(movetopos[0],movetopos[1]);
      self.canvasContext.lineTo(linetopos[0],linetopos[1]);
      // self.canvasContext.moveTo(linetopos[0],linetopos[1]);
      // self.canvasContext.lineTo(movetopos[0],movetopos[1]);
    }
  });
  this.canvasContext.stroke();
},
//随机数生成器(小数)
fRandomByfloat:function(under, over){
  return under+Math.random()*(over-under);
},
//随机数生成器(整数)
fRandomBy:function(under, over){
  switch(arguments.length){
    case 1: return parseInt(Math.random()*under+1);
    case 2: return parseInt(Math.random()*(over-under+1) + under);
    default: return 0;
  }
},
//根据当前产汇流场extent随机生成粒子
randomParticle: function (particle) {
  let safe = 30,x=-1, y=-1,lng=null,lat=null;
  let hasextent = this.extent.length!=0;
  let calc_extent = hasextent?this.extent:this.initExtent;
  try{
    do {
      try{
        if(hasextent){
          let pos_x = this.fRandomBy(0,this.canvasWidth);
          let pos_y = this.fRandomBy(0,this.canvasHeight);
          let cartesian = this.viewer.camera.pickEllipsoid(new Cartesian2(pos_x, pos_y), this.viewer.scene.globe.ellipsoid);
          let cartographic = this.viewer.scene.globe.ellipsoid.cartesianToCartographic(cartesian);
          if(cartographic){
            //将弧度转为度的十进制度表示
            lng = CMath.toDegrees(cartographic.longitude);
            lat = CMath.toDegrees(cartographic.latitude);
          }
        }else{
          lng = this.fRandomByfloat(calc_extent[0],calc_extent[1]);
          lat = this.fRandomByfloat(calc_extent[2],calc_extent[3]);
        }
      }catch(e){

      }
      if(lng){
        let gridpos = this._togrid(lng,lat);
        x = gridpos[0];
        y = gridpos[1];
      }
    } while (this.windField.getIn(x, y)[2] <= 0 && safe++ < 30);
  }catch (e) {
  }
  try{
    let field = this.windField;
    let uv = field.getIn(x, y);
    particle.speed = uv[2];
    particle.lng = lng;
    particle.lat = lat;
    particle.x = x;
    particle.y = y;
    let nextLng = lng +  this.calc_speedRate[0] * uv[0];
    let nextLat = lat +  this.calc_speedRate[1] * uv[1];
    particle.tlng = nextLng;
    particle.tlat = nextLat;
    particle.age = Math.round(Math.random() * this.maxAge);//每一次生成都不一样

  }
  catch (e) {

  }
  return particle;
}

最后分享下地图下载器下载地址

通过百度网盘分享的文件:V-2.0jbr…
链接:https://pan.baidu.com/s/1AiFKTTknkEHkJ7t4nQ2P1g 
提取码:8664
复制这段内容打开「百度网盘APP 即可获取」

如果对您有所帮助,请点赞打赏支持!

技术合作交流qq:2401315930

  • 23
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

合抱阴阳

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值