import path from 'path'
import fs from 'fs'
import process from 'process'
import get from 'lodash-es/get.js'
import each from 'lodash-es/each.js'
import genID from 'wsemi/src/genID.mjs'
import str2b64 from 'wsemi/src/str2b64.mjs'
import j2o from 'wsemi/src/j2o.mjs'
import execScript from 'wsemi/src/execScript.mjs'
import fsIsFile from 'wsemi/src/fsIsFile.mjs'
import isestr from 'wsemi/src/isestr.mjs'
import isarr from 'wsemi/src/isarr.mjs'
import isearr from 'wsemi/src/isearr.mjs'
import iseobj from 'wsemi/src/iseobj.mjs'
import isnum from 'wsemi/src/isnum.mjs'
import cint from 'wsemi/src/cint.mjs'
import cstr from 'wsemi/src/cstr.mjs'
import cdbl from 'wsemi/src/cdbl.mjs'
let fdSrv = path.resolve()
function isWindows() {
return process.platform === 'win32'
}
function getExecFolder() {
let fnExe = `kriging.exe`
let fdExeSrc = `${fdSrv}/src/`
let fdExeNM = `${fdSrv}/node_modules/w-kriging/src/`
if (fsIsFile(`${fdExeSrc}${fnExe}`)) {
return fdExeSrc
}
else if (fsIsFile(`${fdExeNM}${fnExe}`)) {
return fdExeNM
}
else {
return { error: 'can not find executable file for kriging' }
}
}
function getExecPath(fd) {
//fn
let fn = `kriging.exe`
return `${fd}${fn}`
}
/**
* Kriging內外插值,支援2D與3D
*
* @param {Array} psSrc 輸入二維座標加觀測數據點陣列,為[{x:x1,y:y1,z:z1},{x:x2,y:y2,z:z2},...]點物件之陣列,或可為[[x1,y1,z1],[x2,y2,z2],...]點陣列之陣列,亦可支援三維座標加觀測數據點陣列,為[{x:x1,y:y1,z:z1,v:v1},{x:x2,y:y2,z:z2,v:v2},...]點物件之陣列,或可為[[x1,y1,z1,v1],[x2,y2,z2,v2],...]點陣列之陣列
* @param {Array|Object} psTar 輸入二維座標點陣列或點物件,為[{x:x1,y:y1},{x:x2,y:y2},...]點物件之陣列,或{x:x1,y:y1}點物件,亦可支援三維座標點陣列或點物件,為[{x:x1,y:y1,z:z1},{x:x2,y:y2,z:z2},...]點物件之陣列,或{x:x1,y:y1,z:z1}點物件
* @param {Object} [opt={}] 輸入設定物件,預設{}
* @param {String} [opt.keyX='x'] 輸入點物件之x欄位字串,為座標,預設'x'
* @param {String} [opt.keyY='y'] 輸入點物件之y欄位字串,為座標,預設'y'
* @param {String} [opt.keyZ='z'] 輸入點物件之z欄位字串,若為二維則為觀測值,若為三維則為座標,預設'z'
* @param {String} [opt.keyV='v'] 輸入點物件之v欄位字串,為觀測值,預設'v'
* @param {String} [opt.variogram_model='exponential'] 輸入變異圖模式字串,可選'linear'、'power'、'gaussian'、'spherical'、'exponential'、'hole-effect',其定義詳見pykrige,預設'exponential'
* @param {Integer} [opt.nlags=9] 輸入變異圖統計直條圖數量整數,其定義詳見pykrige,預設9
* @returns {Promise} 回傳Promise,resolve回傳成功訊息,reject回傳錯誤訊息
* @example
*
* async function test2d1() {
*
* let psSrc = [
* {
* x: -0.1, y: -0.1, z: 0
* },
* {
* x: 1, y: 0, z: 0
* },
* {
* x: 1, y: 1, z: 10
* },
* {
* x: 0, y: 1, z: 0
* },
* ]
* let psTar = [
* { x: 0.1, y: 0.95 },
* ]
* let opt = {
* variogram_model: 'gaussian',
* nlags: 9,
* }
*
* let r = await WKriging(psSrc, psTar, opt)
* console.log('test2d1', r)
* // => test2d [ { x: 0.1, y: 0.95, z: 1.8997805977145759 } ]
*
* }
* test2d1()
* .catch((err) => {
* console.log('catch', err)
* })
*
* async function test2d2() {
*
* let psSrc = [{ x: 243, y: 206, z: 95 }, { x: 233, y: 225, z: 146 }, { x: 21, y: 325, z: 22 }, { x: 953, y: 28, z: 223 }, { x: 1092, y: 290, z: 39 }, { x: 744, y: 200, z: 191 }, { x: 174, y: 3, z: 22 }, { x: 537, y: 368, z: 249 }, { x: 1151, y: 371, z: 86 }, { x: 814, y: 252, z: 125 }]
*
* let psTar = [{
* x: 243,
* y: 205,
* }]
*
* let opt = {
* variogram_model: 'exponential',
* nlags: 9,
* }
*
* let r = await WKriging(psSrc, psTar, opt)
* console.log('test2d2', r)
* // => test2d [ { x: 243, y: 205, z: 94.89492366904084 } ]
*
* }
* test2d2()
* .catch((err) => {
* console.log('catch', err)
* })
*
* async function test3d1() {
*
* let psSrc = [
* {
* x: -0.1, y: -0.1, z: -0.1, v: 0
* },
* {
* x: 1, y: 0, z: 0, v: 0
* },
* {
* x: 1, y: 1, z: 0, v: 0
* },
* {
* x: 0, y: 0, z: 1, v: 0
* },
* {
* x: 1, y: 0, z: 1, v: 0
* },
* {
* x: 1, y: 1, z: 1, v: 10
* },
* ]
* let psTar = [
* {
* x: 0.1, y: 0.1, z: 0.95
* },
* ]
* let opt = {
* variogram_model: 'gaussian',
* nlags: 9,
* }
*
* let r = await WKriging(psSrc, psTar, opt)
* console.log('test3d1', r)
* // => test3d [ { x: 0.1, y: 0.1, z: 0.95, v: 1.666666666666666 } ]
*
* }
* test3d1()
* .catch((err) => {
* console.log('catch', err)
* })
*
*/
async function WKriging(psSrc, psTar, opt = {}) {
let errTemp = null
//isWindows
if (!isWindows()) {
return Promise.reject('operating system is not windows')
}
//check psSrc
if (!isearr(psSrc)) {
return Promise.reject('psSrc is not an array')
}
//check psTar
if (!iseobj(psTar) && !isearr(psTar)) {
return Promise.reject('psTar is not an object or array')
}
//isOne
let isOne = iseobj(psTar)
if (isOne) {
psTar = [psTar]
}
//keyX
let keyX = get(opt, 'keyX')
if (!isestr(keyX)) {
keyX = 'x'
}
//keyY
let keyY = get(opt, 'keyY')
if (!isestr(keyY)) {
keyY = 'y'
}
//keyZ
let keyZ = get(opt, 'keyZ')
if (!isestr(keyZ)) {
keyZ = 'z'
}
//keyV
let keyV = get(opt, 'keyV')
if (!isestr(keyV)) {
keyV = 'v'
}
//gv
let gv = (p) => {
let x = get(p, keyX, '')
let p0 = get(p, 0, '')
let y = get(p, keyY, '')
let p1 = get(p, 1, '')
let z = get(p, keyZ, '')
let p2 = get(p, 2, '')
let v = get(p, keyV, '')
let p3 = get(p, 3, '')
let bx = isnum(x)
let by = isnum(y)
let bz = isnum(z)
let bv = isnum(v)
if (bx) {
x = cdbl(x)
}
else if (isnum(p0)) {
x = cdbl(p0)
}
else {
x = null
}
if (by) {
y = cdbl(y)
}
else if (isnum(p1)) {
y = cdbl(p1)
}
else {
y = null
}
if (bz) {
z = cdbl(z)
}
else if (isnum(p2)) {
z = cdbl(p2)
}
else {
z = null
}
if (bv) {
v = cdbl(v)
}
else if (isnum(p3)) {
v = cdbl(p3)
}
else {
v = null
}
return { x, y, z, v }
}
//dtype
let dtype = '2d'
if (true) {
let p0 = get(psSrc, 0, {})
let r = gv(p0)
if (r.x !== null && r.y !== null && r.z !== null && r.v !== null) {
dtype = '3d'
}
}
//arrSrc
let arrSrc = []
each(psSrc, (p) => {
let r = gv(p)
if (dtype === '2d') {
arrSrc.push([r.x, r.y, r.z])
}
else { //dtype==='3d'
arrSrc.push([r.x, r.y, r.z, r.v])
}
})
// console.log('arrSrc', arrSrc)
//arrTar
let arrTar = []
each(psTar, (p) => {
let r = gv(p)
if (dtype === '2d') {
arrTar.push([r.x, r.y])
}
else { //dtype==='3d'
arrTar.push([r.x, r.y, r.z])
}
})
// console.log('arrTar', arrTar)
//variogram_model
let variogram_model = get(opt, 'variogram_model', '')
if (!isestr(variogram_model)) {
variogram_model = 'exponential'
}
//nlags
let nlags = get(opt, 'nlags', '')
if (!isnum(nlags)) {
nlags = 9
}
nlags = cint(nlags)
//fdExe
let fdExe = getExecFolder()
//check
if (get(fdExe, 'error')) {
return Promise.reject(fdExe.error)
}
//prog
let prog = getExecPath(fdExe)
//id
let id = genID()
//fpIn
let fpIn = `${fdExe}_${id}_fpIn.json`
//fpIn
let fpOut = `${fdExe}_${id}_fpOut.json`
//rIn
let rIn = {
src: arrSrc,
pred: arrTar,
}
//save
fs.writeFileSync(fpIn, JSON.stringify(rIn), 'utf8')
//inp
let inp = {
fpIn,
fpOut,
opt: {
variogram_model,
nlags,
},
}
// console.log('inp', inp)
//input to b64
let cInput = JSON.stringify(inp)
let b64Input = str2b64(cInput)
//execScript
await execScript(prog, b64Input)
.catch((err) => {
console.log('WKriging execScript catch', err)
errTemp = err
})
//read output
let j = fs.readFileSync(fpOut, 'utf8')
// console.log('j', j)
let output = j2o(j)
// console.log('output', output)
//unlinkSync
try {
fs.unlinkSync(fpIn)
}
catch (err) {}
//unlinkSync
try {
fs.unlinkSync(fpOut)
}
catch (err) {}
//check
if (errTemp !== null) {
return Promise.reject(errTemp)
}
//check
if (!isarr(output)) {
errTemp = `output[${cstr(output)}] is not an array`
}
//check
if (errTemp !== null) {
return Promise.reject(errTemp)
}
//rs
let rs = []
each(arrTar, (p, k) => {
//v
let v = get(output, k, null)
//push
if (dtype === '2d') {
rs.push({
[keyX]: p[0],
[keyY]: p[1],
[keyZ]: v,
})
}
else { //dtype==='3d'
rs.push({
[keyX]: p[0],
[keyY]: p[1],
[keyZ]: p[2],
[keyV]: v,
})
}
})
if (isOne) {
rs = rs[0]
}
return rs
}
export default WKriging