relaPlasticity.mjs

import join from 'lodash-es/join.js'
import values from 'lodash-es/values.js'
import isNumber from 'lodash-es/isNumber.js'
import cdbl from 'wsemi/src/cdbl.mjs'
import isnum from 'wsemi/src/isnum.mjs'
import iseobj from 'wsemi/src/iseobj.mjs'


// //eps
// let eps = cnst.eps


/**
 * 計算土壤塑性參數:液限LL、塑限PL、塑性指數PI之間互相轉換,至少3給2才能反推全部
 *
 * Unit Test: {@link https://github.com/yuda-lyu/w-geo/blob/master/test/relaPlasticity.test.js Github}
 * @memberOf w-geo
 * @param {Number} [LL=null] 輸入液限數字,單位%,預設null
 * @param {Number} [PI=null] 輸入塑性指數數字,單位%,預設null
 * @param {Number} [PL=null] 輸入塑限數字,單位%,預設null
 * @returns {Object} 回傳物件,含鍵值LL、PI、PL
 * @example
 *
 * let LL = 24 //%
 * let PI = 14 //%
 * let PL = 10 //%
 * let r
 *
 * try {
 *     r = relaPlasticity(LL, null, null)
 * }
 * catch (e) {
 *     r = e.toString()
 * }
 * console.log('LL', r)
 * // => LL { LL: 24, PL: null, PI: null }
 *
 * try {
 *     r = relaPlasticity(null, PI, null)
 *     console.log('PI', r)
 * }
 * catch (e) {
 *     r = e.toString()
 * }
 * // => PI { LL: null, PL: null, PI: 14 }
 *
 * try {
 *     r = relaPlasticity(null, null, PL)
 * }
 * catch (e) {
 *     r = e.toString()
 * }
 * console.log('PL', r)
 * // => PL { LL: null, PL: 10, PI: null }
 *
 * try {
 *     r = relaPlasticity(LL, PI, null)
 * }
 * catch (e) {
 *     r = e.toString()
 * }
 * console.log('LL,PI', r)
 * // => LL,PI { LL: 24, PL: 10, PI: 14 }
 *
 * try {
 *     r = relaPlasticity(LL, null, PL)
 * }
 * catch (e) {
 *     r = e.toString()
 * }
 * console.log('LL,PL', r)
 * // => LL,PL { LL: 24, PL: 10, PI: 14 }
 *
 * try {
 *     r = relaPlasticity(null, PI, PL)
 * }
 * catch (e) {
 *     r = e.toString()
 * }
 * console.log('PI,PL', r)
 * // => PI,PL { LL: 24, PL: 10, PI: 14 }
 *
 * try {
 *     r = relaPlasticity(LL, PI, PL)
 * }
 * catch (e) {
 *     r = e.toString()
 * }
 * console.log('LL,PI,PL', r)
 * // => LL,PI,PL { LL: 24, PL: 10, PI: 14 }
 *
 * try {
 *     r = relaPlasticity(2, PI, PL)
 * }
 * catch (e) {
 *     r = e.toString()
 * }
 * console.log('2,PI,PL', r)
 * // => 2,PI,PL {
 * //   LL: 2,
 * //   PL: 10,
 * //   PI: 14,
 * //   err: '液限[2]<=塑限[10], 反算出塑限[-12]<=0, 反算出塑性指數[-8]<=0, 輸入液限[2]與反算出液限[24]差距過大'
 * // }
 *
 * try {
 *     r = relaPlasticity(32, PI, PL)
 * }
 * catch (e) {
 *     r = e.toString()
 * }
 * console.log('32,PI,PL', r)
 * // => 32,PI,PL {
 * //   LL: 32,
 * //   PL: 10,
 * //   PI: 14,
 * //   err: '輸入塑限[10]與反算出塑限[18]差距過大, 輸入塑性指數[14]與反算出塑性指數[22]差距過大, 輸入液限[32]與反算出液限[24]差距過大'
 * // }
 *
 */
function relaPlasticity(LL, PI, PL, WC = null) {
    let kpErr = {} //非中斷報錯訊息

    //LL, %
    if (isnum(LL)) {
        LL = cdbl(LL)
        if (LL <= 0) {
            kpErr['LL'] = `液限[${LL}]為數字但<=0,自動清除`
        }
    }
    else {
        LL = null
    }

    //PL, %
    if (isnum(PL)) {
        PL = cdbl(PL)
        if (PL <= 0) {
            kpErr['PL'] = `塑限[${PL}]為數字但<=0,自動清除`
        }
    }
    else {
        PL = null
    }

    //PI, %
    if (isnum(PI)) {
        PI = cdbl(PI)
        if (PI <= 0) {
            kpErr['PI'] = `塑性指數[${PI}]為數字但<=0,自動清除`
        }
    }
    else {
        PI = null
    }

    function core() {
        let bUpdate = false

        //LL>PL
        if (isNumber(LL) && isNumber(PL)) {
            if (LL <= PL) {
                kpErr['ck_LL_PL'] = `液限[${LL}]<=塑限[${PL}]`
            }
        }

        //LL-PI=PL
        let _PL
        if (isNumber(LL) && isNumber(PI)) {
            _PL = LL - PI
        }
        if (isNumber(_PL)) {
            if (!isNumber(PL)) {
                // console.log('set PL', _PL)
                PL = _PL
                bUpdate = true
            }
            else {
                // console.log('b1 PL', PL, _PL)
                if (_PL <= 0) {
                    kpErr['ck_PL'] = `反算出塑限[${_PL}]<=0`
                }
                else if (_PL >= 100) {
                    kpErr['ck_PL'] = `反算出塑限[${_PL}]>=100`
                }
                else if (Math.abs(PL - _PL) > _PL / 100 * 5) {
                    kpErr['ck_PL'] = `輸入塑限[${PL}]與反算出塑限[${_PL}]差距過大`
                }
            }
        }

        //PI=LL-PL
        let _PI
        if (isNumber(LL) && isNumber(PL)) {
            _PI = LL - PL
        }
        if (isNumber(_PI)) {
            if (!isNumber(PI)) {
                // console.log('set PI', _PI)
                PI = _PI
                bUpdate = true
            }
            else {
                // console.log('b2 PI', PI, _PI)
                if (_PI <= 0) {
                    kpErr['ck_PI'] = `反算出塑性指數[${_PI}]<=0`
                }
                else if (_PI >= 100) {
                    kpErr['ck_PI'] = `反算出塑性指數[${_PI}]>=100`
                }
                else if (Math.abs(PI - _PI) > _PI / 100 * 5) {
                    kpErr['ck_PI'] = `輸入塑性指數[${PI}]與反算出塑性指數[${_PI}]差距過大`
                }
            }
        }

        //PL+PI=LL
        let _LL
        if (isNumber(PL) && isNumber(PI)) {
            _LL = PL + PI
        }
        if (isNumber(_LL)) {
            if (!isNumber(LL)) {
                // console.log('set LL', _LL)
                LL = _LL
                bUpdate = true
            }
            else {
                // console.log('b3 LL', LL, _LL)
                if (_LL <= 0) {
                    kpErr['ck_LL'] = `反算出液限[${_LL}]<=0`
                }
                else if (_LL >= 100) {
                    kpErr['ck_LL'] = `反算出液限[${_LL}]>=100`
                }
                else if (Math.abs(LL - _LL) > _LL / 100 * 5) {
                    kpErr['ck_LL'] = `輸入液限[${LL}]與反算出液限[${_LL}]差距過大`
                }
            }
        }

        return bUpdate
    }

    //check 至少要2參數才進行轉換
    let ieff = 0
    ieff += isnum(LL) ? 1 : 0
    ieff += isnum(PL) ? 1 : 0
    ieff += isnum(PI) ? 1 : 0
    // console.log('ieff', ieff)
    if (ieff >= 2) {
        let b = core()
        // console.log('core1')
        while (b) {
            b = core()
            // console.log('core2')
        }
    }

    //LI, CI
    //CI<=0 : 流體狀,具流動性
    //0<CI<=1 : 塑體狀,具塑狀性質
    //CI>1 : 固體狀,具固體或半固體狀
    //CI與LI之和為1
    let LI = null //液性指數
    let CI = null //稠度指數
    if (isnum(WC) && isnum(PL) && isnum(LL) && PI > 0) {
        WC = cdbl(WC)
        LI = (WC - PL) / PI
        CI = (LL - WC) / PI
        if (!isnum(LI)) {
            console.log('WC', WC)
            console.log('PL', PL)
            throw new Error(`內插LI[${LI}]時發生錯誤`)
        }
        if (!isnum(CI)) {
            console.log('WC', WC)
            console.log('LL', LL)
            throw new Error(`內插CI[${CI}]時發生錯誤`)
        }
    }

    //r
    let r = {
        LL,
        PL,
        PI,
        WC,
        LI,
        CI,
    }
    if (iseobj(kpErr)) {
        let err = join(values(kpErr), ', ')
        r.err = err
    }

    return r
}


export default relaPlasticity