如何利用vue实现波谱拟合详解


Posted in Javascript onNovember 05, 2020

主页面-功能介绍

小白初入职场第一篇总结,废话比较多,求轻喷~

如何利用vue实现波谱拟合详解

波谱拟合用来对某种材料或物质的谱图进行识别和分析,每种物质可以有多种成分,每种成分用component1、component2...表示,用Add another component和Remove component来控制每种成分的增加和删除,每种成分由多种原子核构成,即nuclei,用Add nucleus和Remove nucleus来控制每种成分内原子核数量,每新增一个原子核,波谱就会分裂一次,谱峰数量由(1->2->4->8...)依次分裂。另外可以通过更改默认参数,改变波谱形态,成分参数中:Relative amount表示每种成分占绘图分量的百分比,百分比之和不超过100,giso用来计算分裂的中心位置,LineWidth用来控设置谱峰到谱谷的宽度,%Lorentzian表示谱峰形态,一共两种形态,高斯和洛伦兹,两者之和为100;原子核参数:No of equivalent nuclei用来改变原子核个数,如果一种成分内包含很多个一模一样的参数时,就可以通过改变这个参数实现,Nuclear spin用来改变原子核种类,Hyperfine用来设置分裂后两峰之间的宽度。

再来一张图:

如何利用vue实现波谱拟合详解

每种成分数量和参数、每种成分内每种原子核数量和参数设置好后,对数据进行处理,由三种结果,卷积、积分、二重积分,那就来看看数据的处理逻辑吧~

如何利用vue实现波谱拟合详解

从数据流角度,主要进行三步处理:数据->数据裂变->光谱计算->绘图,左边是算法实现所需的参数、右边是对数据及每个步骤的描述。

代码实现

遇到一个坑,一开始写demo的时候用的vue+Ant design of vue,在select等其他组件的使用上都是正常的,但是在input number中就很变态了,给input number绑定的change事件,用户在输入两位以上数据的时候,change事件会触发两次!!!想避免这个问题,于是用blur事件,问题又来了,因为这个页面中组件的生成和删除需要动态渲染,并且根据前面的介绍很容易知道组件的渲染是有两层结构的,那么在用户进行点击或输入操作的时候,就需要传递一个参数(用来定位是哪个component以及每个component下面对应的某一个nucle等等),能力有限( ?□? )目前我没有找到解决办法,于是转elementUI框架。

组件的动态渲染用了一个比较巧妙的办法,一开始我打算用render来写,后来从部门大神那里学到通过遍历列表进行渲染,脑子之间还是有差距的。。。

<div v-for="(Con, i) in componentList" :key="Con[i]"><strong>Component {{i+1}}.</div>

同理原子核的动态渲染也是这么实现的:

<div v-for="(li, j) in nucleusList[i]" :key="li[j]">{{j+1}}. No of equivalent nuclei:</div>

然后每次增加和删除只需要操作数组列表的长度即可~

各参数的绑定:component中参数均使用一维数组,chenge事件需传递一维数组的下标,component内的nucleui均使用二维数组,change事件需传递二维数组的下标。

以上介绍参数定义,接下来是数据处理:

// 首先计算裂变数据
stickspectrum (w) {
   // console.log('组件信息', w)
   const stick = new Array(2) // 返回包含stick[0]的stick光谱数组,stick[1]是位置
   stick[0] = new Array()// 光谱强度
   stick[1] = new Array()// 光谱位置
   stick[1][0] = this.h * this.frequency / (this.r[w].g * this.mu)

   for (var j = 0; j < this.r[w].equiv.length; j++) {
    // console.log('stick[0].length', stick[0].length) //分裂后的光谱数据长度
    for (var i = stick[0].length - 1; i >= 0; i--) {
     stick[0][i] /= Math.pow((2 * this.r[w].spin[j] + 1), this.r[w].equiv[j])
     stick[1][i] -= this.r[w].equiv[j] * this.r[w].spin[j] * this.r[w].hfc[j]

     for (var k = 0; k < 2 * this.r[w].equiv[j] * this.r[w].spin[j]; k++) {
      stick[1].splice(i + k + 1, 0, stick[1][i] + this.r[w].hfc[j] * (k + 1))
      stick[0].splice(i + k + 1, 0, 0)
     }
     for (var k = 0; k < this.r[w].equiv[j]; k++) {
      for (var m = i + 2 * this.r[w].spin[j] * k; m >= i; m--) {
       for (var ii = 0; ii < 2 * this.r[w].spin[j]; ii++) {
        stick[0][m + ii + 1] += stick[0][m]
       }
      }
     }
    }
   }
   return stick
  },
// 再对裂变后的数据进行光谱计算
spectrum (stick) {
   let xmin = Infinity; let xmax = 0
   for (var k = 0; k < this.r.length; k++) {
    xmin = Math.min(Math.min.apply(Math, stick[k][1]) - 10 * this.r[k].width, xmin)
    xmax = Math.max(Math.max.apply(Math, stick[k][1]) + 10 * this.r[k].width, xmax)
   }
   const tmp = xmax - xmin
   xmax += tmp * 0.05
   xmin -= tmp * 0.05
   const step = (xmax - xmin) / (this.No_integers - 1)
   for (let i = 0; i < this.No_integers; i++) {
    this.XY[0][i][0] = xmin + step * i
    this.XY[0][i][1] = 0
    this.XYint[0][i][0] = this.XY[0][i][0]
    this.XYint[0][i][1] = 0
    this.XYdoubleint[0][i][0] = this.XY[0][i][0]
    this.XYdoubleint[0][i][1] = 0
   }

   for (let k = 0; k < this.r.length; k++) { // 分量累加
    const sticks = new Array(this.No_integers)
    for (var i = 0; i < stick[k][0].length; i++) {
     var j = Math.round((stick[k][1][i] - xmin) / step)
     sticks[j] = sticks[j] ? sticks[j] + stick[k][0][i] : stick[k][0][i]
    }

    const tmp = new Array(this.No_integers)// 第一种光谱绘图位置数据
    let ind = 0
    for (var i = 0; i < this.No_integers; i++) {
     if (sticks[i]) { // 建立峰值索引——sticks[i]===1即峰值所在。
      tmp[ind] = i
      ind++
     }
    }
    const tmpint = new Array(this.No_integers) // 用来保存每个分量的积分
    const tmpdoubleint = new Array(this.No_integers) // 用来保存每个分量的二重积分
    for (var i = 0; i < this.No_integers; i++) tmpint[i] = 0
    tmpdoubleint[0] = 0
    const rwid = Number(this.r[k].width)
    const rwid2 = Math.pow(rwid, 2)
    const lortmp = Number(this.r[k].percent) * Number(this.r[k].lor) / 100 * Math.sqrt(3) / Math.PI // 洛伦兹线乘积
    const gaustmp = Number(this.r[k].percent) * (100 - Number(this.r[k].lor)) / 100 * Math.sqrt(2 / Math.PI) // 高斯线乘法器

    for (let i = 0; i < this.No_integers; i++) {
     for (let j = 0; j < ind; j++) {
      const delta = this.XY[0][i][0] - this.XY[0][tmp[j]][0]
      const delta2 = Math.pow(delta, 2)
      if ((rwid > step && Math.abs(-0.5 * rwid - delta) < 0.5 * step) || (rwid < step && -0.5 * rwid - delta > 0 && -0.5 * rwid - delta < step)) {
       this.XY[0][i][1] += sticks[tmp[j]] * (lortmp * 0.5 / rwid2 + gaustmp * 2 / Math.sqrt(Math.E) / rwid2)
      } else if ((rwid > step && Math.abs(0.5 * rwid - delta) < 0.5 * step) || (rwid < step && delta - 0.5 * rwid > 0 && delta - 0.5 * rwid < step)) {
       this.XY[0][i][1] -= sticks[tmp[j]] * (lortmp * 0.5 / rwid2 + gaustmp * 2 / Math.sqrt(Math.E) / rwid2)
      } else {
       this.XY[0][i][1] += sticks[tmp[j]] * (gaustmp * (-4) / rwid / rwid2 * delta * Math.exp(-2 * delta2 / rwid2) + lortmp * (-delta) * rwid / Math.pow((delta2 + 3 / 4 * rwid2), 2)) // 其他情况下的正常计算,高斯+洛伦兹
      }
      this.dataarray = [this.XY, this.XYint, this.XYdoubleint]
      tmpint[i] += sticks[tmp[j]] * (gaustmp * Math.exp(-2 * delta2 / rwid2) / rwid + lortmp / 2 / rwid / (0.75 + delta2 / rwid2)) // 高斯+洛伦兹积分-明确计算以避免积分误差
     }
    }
    for (let j = 1; j < this.No_integers; j++) {
     tmpdoubleint[j] = tmpdoubleint[j - 1] + step * (tmpint[j] + tmpint[j - 1]) / 2
    } // 二重积分
    // console.log('二重积分', tmpdoubleint)

    const mm = tmpdoubleint[this.No_integers - 1] / Number(this.r[k].percent) // 有多少积分高于理论(只发生在非常尖锐的线)
    for (let j = 1; j < this.No_integers; j++) {
     this.XYdoubleint[0][j][1] += mm > 1 ? tmpdoubleint[j] / mm : tmpdoubleint[j] // 第三种频谱数据 如果二重积分高于理论,将其标准化
     this.XYint[0][j][1] += tmpint[j] // 第二种频谱数据
    }
   }
   // console.log('XYint', this.XYint[0])
  },

计算完成的光谱,返回三种数据XY、XYint、XYdouble,然后就是绘图~

到此这篇关于如何利用vue实现波谱拟合的文章就介绍到这了,更多相关vue实现波谱拟合内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Javascript 相关文章推荐
javascript对象的property和prototype是这样一种关系
Mar 24 Javascript
JavaScript为对象原型prototype添加属性的两种方式
Aug 01 Javascript
Knockout text绑定DOM的使用方法
Nov 15 Javascript
JS如何实现文本框随文本的长度而增长
Jul 30 Javascript
javaScript知识点总结(必看篇)
Jun 10 Javascript
浅谈json取值(对象和数组)
Jun 24 Javascript
JQuery ZTree使用方法详解
Jan 07 Javascript
Thinkjs3新手入门之如何使用静态资源目录
Dec 06 Javascript
Angular实现点击按钮后在上方显示输入内容的方法
Dec 27 Javascript
JS html事件冒泡和事件捕获操作示例
May 01 Javascript
小程序和web画三角形实现解析
Sep 02 Javascript
javascript实现数字时钟效果
Feb 06 Javascript
关于Vue中$refs的探索浅析
Nov 05 #Javascript
JavaScript 实现轮播图特效的示例
Nov 05 #Javascript
nuxt 服务器渲染动态设置 title和seo关键字的操作
Nov 05 #Javascript
nuxt 每个页面head标签内容设置方式
Nov 05 #Javascript
JavaScript TAB栏切换效果的示例
Nov 05 #Javascript
nuxt 页面路由配置,主页轮播组件开发操作
Nov 05 #Javascript
JS时间戳与日期格式互相转换的简单方法示例
Jan 30 #Javascript
You might like
JAVA/JSP学习系列之二
2006/10/09 PHP
php中的常用魔术方法汇总
2016/02/14 PHP
javascript 简单高效判断数据类型 系列函数 By shawl.qiu
2007/03/06 Javascript
iis6+javascript Add an Extension File
2007/06/13 Javascript
完整显示当前日期和时间的JS代码
2007/09/17 Javascript
Extjs中TabPane如何嵌套在其他网页中实现思路及代码
2013/01/27 Javascript
Javascript 按位与运算符 (&amp;)使用介绍
2014/02/04 Javascript
JavaScript中setUTCMilliseconds()方法的使用详解
2015/06/12 Javascript
AngularJS的一些基本样式初窥
2015/07/27 Javascript
学JavaScript七大注意事项【必看】
2016/05/04 Javascript
Node.js环境下编写爬虫爬取维基百科内容的实例分享
2016/06/12 Javascript
关于JS Lodop打印插件打印Bootstrap样式错乱问题的解决方案
2016/12/23 Javascript
基于vue-ssr服务端渲染入门详解
2018/01/08 Javascript
解决vue-cli单页面手机应用input点击手机端虚拟键盘弹出盖住input问题
2018/08/25 Javascript
文章或博客自动生成章节目录索引(支持三级)的实现代码
2020/05/10 Javascript
通过js随机函数Math.random实现乱序
2020/05/19 Javascript
vue使用keep-alive实现组件切换时保存原组件数据方法
2020/10/30 Javascript
Vue-router编程式导航的两种实现代码
2021/03/04 Vue.js
[02:43]2018DOTA2亚洲邀请赛主赛事首日TOP5
2018/04/04 DOTA
[57:24]LGD vs VGJ.T 2018国际邀请赛小组赛BO2 第二场 8.16
2018/08/17 DOTA
python的random模块及加权随机算法的python实现方法
2017/01/04 Python
Python之Scrapy爬虫框架安装及使用详解
2017/11/16 Python
python判断完全平方数的方法
2018/11/13 Python
Django对models里的objects的使用详解
2019/08/17 Python
详解python中index()、find()方法
2019/08/29 Python
TensorFlow实现自定义Op方式
2020/02/04 Python
如何把外网python虚拟环境迁移到内网
2020/05/18 Python
css3实现一个div设置多张背景图片及background-image属性实例演示
2017/08/10 HTML / CSS
美国滑雪板和装备购物网站:Skis.com
2018/12/20 全球购物
上课迟到检讨书100字
2014/01/11 职场文书
拖鞋店创业计划书
2014/01/15 职场文书
大学生实习鉴定评语
2014/04/25 职场文书
大学生个人求职信
2014/06/02 职场文书
公司更名通知函
2015/04/24 职场文书
2016高校自主招生自荐信范文
2016/01/28 职场文书
导游词之西江千户苗寨
2019/12/24 职场文书