상당히 큰 JMP 데이터 테이블(132k 행, 2860개 열)이 있는데 여기에는 많은 수의 수식 열(200개 이상)도 있습니다.나는 정기적으로 새 데이터를 이 파일로 가져오기 때문에 새 데이터가 추가될 때 자동으로 채워지도록 모든 수식 열을 "라이브" 상태로 유지하려고 합니다.수식 재계산 속도에 문제가 생기기 시작했습니다.
처음에 수식은 대부분 단순한 산술(다른 열 값의 더하기/빼기/곱하기)이었고 속도는 문제가 되지 않았습니다.그러나 더 복잡한 몇 가지 수식을 추가하기 시작했으며 이로 인해 이 표의 모든 수식을 다시 계산하는 데 걸리는 시간이 크게 증가했습니다.
OnOpen 스크립트를 사용하여 수식 평가를 자동으로 억제하고(기본 설정 옵션인 "열 때 수식 평가 억제"가 작동하지 않기 때문에) 데이터 가져오기 스크립트를 사용하여 Excel에서 새 데이터를 가져오고 수식을 평가한 다음 다시 억제합니다. 수식 평가.가져오기 스크립트를 완료하는 데 15분이 걸리는 지점에 이르렀고 JMP는 완전히 잠겨 있고 전체 시간 동안 응답하지 않습니다.나는 그 15분의 대부분을 차지하는 몇 가지 특정 수식 열을 정확히 지적할 수 있습니다.
계산 속도를 최적화하는 방법에 대한 아이디어가 있는 사람이 있는지 궁금합니다.예를 들어:
- 내 JSL 코드가 비효율적으로 작성되어 개선될 수 있습니까?
- 수식은 실제로 추가되는 새 행에 대해서만 평가하면 되지만(일반적으로 한 번에 50개 이하의 행) 재계산 시간으로 인해 전체 132k 행이 매번 평가되고 있다고 믿게 됩니다.특정 행에 대해 부분 평가를 수행하는 방법이 있습니까?
다음은 더 느린 수식 중 하나의 예입니다.테이블의 각 행에 있는 원시 점도 값을 기준으로 수정된 제품 점도를 계산합니다.제품 등급에 따라 계산이 달라지므로 등급별 정보를 얻기 위해 조회가 수행됩니다.GradeSpecs:찾기 제품 데이터를 포함하는 연관 배열이며 테이블의 OnOpen 스크립트에서 정의됩니다.
Names Default To Here( 1 );
myGrade = :Name( "##run_grade_jmp" );
Try(
If( Namespace Exists( "GradeSpecs" ),
Visc_Property = GradeSpecs:find[myGrade]["Prod Visc"]["Property"];
If( Visc_Property == "xyzTestMethod",
xyz_Target = GradeSpecs:find[myGrade]["Prod Visc"]["Target"];
xyz_corrected_value = :Name( "xyz1_Value" ) * xyz_Target / :Name( "xyz2_Value" )) ^ 1.333;
,
xyz_corrected_value = Empty()
);
,
xyz_corrected_value = Empty()
)
,
xyz_corrected_value = Empty()
);
xyz_corrected_value;
여기 또 다른 예가 있습니다.ThermoCH:RxEffDenZ 함수는 OnOpen 스크립트에 정의된 사용자 지정 함수입니다.또한 많은 매개변수가 연관 배열로 ThermoCH 네임스페이스에 정의되어 있습니다.
ThermoCH:RxEffDenZ(
:Pressure,
:Temp,
:z1conc,
(z2conc+z3conc),
(z4conc+z4conc),
0,
0,
0,
0
)
RxEffDenZ의 정의는 다음과 같습니다.
ThermoCH:RxEffDenZ = Function(
//parameters
{dPressure_PSIG, dTemp_DEGF, dz4_wf, dz1_wf, dz2_wf, dz5_wf, dz6_wf, dz7_wf, dz3_wf},
//local variables
{, T1, T2, P3, TOTWF, iz4SF, z1SF, z2SF, z5SF, z7SF, z3SF, TOTMOL, Iz4, z1, z2, z5, z7, z3, Mw, ac_z1, ac_z2, ac_z4,
ac_z5, ac_z7, ac_z3, tr_z4, tr_z1, tr_z2, tr_z5, tr_z7, tr_z3, psat_z4, psat_z1, psat_z2, psat_z5, psat_z7, psat_z3, k_z4,
k_z1, k_z2, k_z5, k_z7, k_z3, alpha_z4, alpha_z1, alpha_z2, alpha_z5, alpha_z7, alpha_z3, a_z4, a_z1, a_z2, a_z5, a_z7, a_z3,
delta_1, delta_2, delta_3, delta_4, delta_5, delta_6, delta_7, delta_8, delta_9, delta_10, delta_11, delta_12, delta_13,
delta_14, delta_15, am, bm, pr_c1, pr_z1, pr_z2, q, r, D, radian, theta, v, i, S_1A, s_1, T_1A, T_1, den,
x1, x2, x3, S, T, Sprime, Tprime},
T1 = dTemp_DEGF + 459.67; //Convert F to R
T2 = T1 * (5 / 9); //Convert R to K
P3 = (dPressure_PSIG + 14.696) * 6894.757293178; //Convert psig to Pa
TOTWF = dz4_wf + dz1_wf + dz2_wf + dz5_wf + dz7_wf + dz3_wf;
iz4SF = dz4_wf / TOTWF;
z1SF = dz1_wf / TOTWF;
z2SF = dz2_wf / TOTWF;
z5SF = dz5_wf / TOTWF;
z7SF = dz7_wf / TOTWF;
z3SF = dz3_wf / TOTWF;
// Determine mole fraction of solvent components
TOTMOL = iz4SF / ThermoCH:MW["z4"] + z1SF / ThermoCH:MW["z1"] + z2SF / ThermoCH:MW["z2"] + z5SF / ThermoCH:MW["z5"] + z7SF
/ ThermoCH:MW["z7"] + z3SF / ThermoCH:MW["z3"];
Iz4 = iz4SF / ThermoCH:MW["z4"] / TOTMOL;
z1 = z1SF / ThermoCH:MW["z1"] / TOTMOL;
z2 = z2SF / ThermoCH:MW["z2"] / TOTMOL;
z5 = z5SF / ThermoCH:MW["z5"] / TOTMOL;
z7 = z7SF / ThermoCH:MW["z7"] / TOTMOL;
z3 = z3SF / ThermoCH:MW["z3"] / TOTMOL;
Mw = Iz4 * ThermoCH:MW["z4"] + z1 * ThermoCH:MW["z1"] + z2 * ThermoCH:MW["z2"] + z5 * ThermoCH:MW["z5"] + z7 * ThermoCH:MW[
"z7"] + z3 * ThermoCH:MW["z3"];
//a factors
ac_z4 = 0.45724 * 8.3143 ^ 2 * ThermoCH:Tc["z4"] ^ 2 / (ThermoCH:Pc["z4"] * 10 ^ 5);
ac_z1 = 0.45724 * 8.3143 ^ 2 * ThermoCH:Tc["z1"] ^ 2 / (ThermoCH:Pc["z1"] * 10 ^ 5);
ac_z2 = 0.45724 * 8.3143 ^ 2 * ThermoCH:Tc["z2"] ^ 2 / (ThermoCH:Pc["z2"] * 10 ^ 5);
ac_z5 = 0.45724 * 8.3143 ^ 2 * ThermoCH:Tc["z5"] ^ 2 / (ThermoCH:Pc["z5"] * 10 ^ 5);
ac_z7 = 0.45724 * 8.3143 ^ 2 * ThermoCH:Tc["z7"] ^ 2 / (ThermoCH:Pc["z7"] * 10 ^ 5);
ac_z3 = 0.45724 * 8.3143 ^ 2 * ThermoCH:Tc["z3"] ^ 2 / (ThermoCH:Pc["z3"] * 10 ^ 5);
tr_z4 = T2 / ThermoCH:Tc["z4"];
tr_z1 = T2 / ThermoCH:Tc["z1"];
tr_z2 = T2 / ThermoCH:Tc["z2"];
tr_z5 = T2 / ThermoCH:Tc["z5"];
tr_z7 = T2 / ThermoCH:Tc["z7"];
tr_z3 = T2 / ThermoCH:Tc["z3"];
//psat in bar
psat_z4 = 10 ^ (6.9895 - 1216.92 / (227.451 + (dTemp_DEGF - 32) * (5 / 9))) * 0.019336721 * 0.068947573;
psat_z1 = 10 ^ (6.96636 - 649.806 / (262.73 + (dTemp_DEGF - 32) * (5 / 9))) * 0.019336721 * 0.068947573;
psat_z2 = 10 ^ (7.01612 - 860.992 / (255.895 + (dTemp_DEGF - 32) * (5 / 9))) * 0.019336721 * 0.068947573;
psat_z5 = 10 ^ (10.413 - 4466.47 / (447.523 + (dTemp_DEGF - 32) * (5 / 9))) * 0.019336721 * 0.068947573;
psat_z7 = 10 ^ (4.05752 - 1353.486 / (T2 + -60.386));
psat_z3 = 10 ^ (4.24696 - 1099.207 / (T2 + -8.256));
k_z4 = 0.37464 + 1.54226 * ThermoCH:w["z4"] - 0.26992 * ThermoCH:w["z4"] ^ 2;
k_z1 = 0.37464 + 1.54226 * ThermoCH:w["z1"] - 0.26992 * ThermoCH:w["z1"] ^ 2;
k_z2 = 0.37464 + 1.54226 * ThermoCH:w["z2"] - 0.26992 * ThermoCH:w["z2"] ^ 2;
k_z5 = 0.37464 + 1.54226 * ThermoCH:w["z5"] - 0.26992 * ThermoCH:w["z5"] ^ 2;
k_z7 = 0.37464 + 1.54226 * ThermoCH:w["z7"] - 0.26992 * ThermoCH:w["z7"] ^ 2;
k_z3 = 0.37464 + 1.54226 * ThermoCH:w["z3"] - 0.26992 * ThermoCH:w["z3"] ^ 2;
alpha_z4 = (1 + k_z4 * (1 - tr_z4 ^ (1 / 2))) ^ 2;
alpha_z1 = (1 + k_z1 * (1 - tr_z1 ^ (1 / 2))) ^ 2;
alpha_z2 = (1 + k_z2 * (1 - tr_z2 ^ (1 / 2))) ^ 2;
alpha_z5 = (1 + k_z5 * (1 - tr_z5 ^ (1 / 2))) ^ 2;
alpha_z7 = (1 + k_z7 * (1 - tr_z7 ^ (1 / 2))) ^ 2;
alpha_z3 = (1 + k_z3 * (1 - tr_z3 ^ (1 / 2))) ^ 2;
a_z4 = alpha_z4 * ac_z4;
a_z1 = alpha_z1 * ac_z1;
a_z2 = alpha_z2 * ac_z2;
a_z5 = alpha_z5 * ac_z5;
a_z7 = alpha_z7 * ac_z7;
a_z3 = alpha_z3 * ac_z3;
delta_1 = 0;
delta_2 = 0;
delta_3 = 0;
delta_4 = 0;
delta_5 = 0;
delta_6 = 0;
delta_7 = 0;
delta_8 = 0;
delta_9 = 0;
delta_10 = 0;
delta_11 = 0;
delta_12 = 0;
delta_13 = 0;
delta_14 = 0;
delta_15 = 0;
am = Iz4 ^ 2 * a_z4 + z1 ^ 2 * a_z1 + z2 ^ 2 * a_z2 + z5 ^ 2 * a_z5 + z7 ^ 2 * a_z7 + z3 ^ 2 * a_z3 + 2 * Iz4 * z1 * (1
-delta_1) * Sqrt( a_z4 * a_z1 ) + 2 * Iz4 * z2 * (1 - delta_2) * Sqrt( a_z4 * a_z2 ) + 2 * Iz4 * z5 * (1 - delta_3) *
Sqrt( a_z4 * a_z5 ) + 2 * Iz4 * z7 * (1 - delta_4) * Sqrt( a_z4 * a_z7 ) + 2 * Iz4 * z3 * (1 - delta_5) * Sqrt( a_z4 * a_z3 )
+ 2 * z1 * z2 * (1 - delta_6) * Sqrt( a_z1 * a_z2 ) + 2 * z1 * z5 * (1 - delta_7) * Sqrt( a_z1 * a_z5 ) + 2 * z1 * z7 *
(1 - delta_8) * Sqrt( a_z1 * a_z7 ) + 2 * z1 * z3 * (1 - delta_9) * Sqrt( a_z1 * a_z3 ) + 2 * z2 * z5 * (1 - delta_10) *
Sqrt( a_z2 * a_z5 ) + 2 * z2 * z7 * (1 - delta_11) * Sqrt( a_z2 * a_z7 ) + 2 * z2 * z3 * (1 - delta_12) *
Sqrt( a_z2 * a_z3 ) + 2 * z5 * z7 * (1 - delta_13) * Sqrt( a_z5 * a_z7 ) + 2 * z5 * z3 * (1 - delta_14) *
Sqrt( a_z5 * a_z3 ) + 2 * z7 * z3 * (1 - delta_15) * Sqrt( a_z7 * a_z3 );
bm = Iz4 * (0.0778 * 8.3143 * ThermoCH:Tc["z4"] / (ThermoCH:Pc["z4"] * 10 ^ 5)) + z1 * (0.0778 * 8.3143 * ThermoCH:Tc["z1"] / (
ThermoCH:Pc["z1"] * 10 ^ 5)) + z2 * (0.0778 * 8.3143 * ThermoCH:Tc["z2"] / (ThermoCH:Pc["z2"] * 10 ^ 5)) + z5 * (0.0778 *
8.3143 * ThermoCH:Tc["z5"] / (ThermoCH:Pc["z5"] * 10 ^ 5)) + z7 * (0.0778 * 8.3143 * ThermoCH:Tc["z7"] / (ThermoCH:Pc["z7"] * 10
^ 5)) + z3 * (0.0778 * 8.3143 * ThermoCH:Tc["z3"] / (ThermoCH:Pc["z3"] * 10 ^ 5));
pr_c1 = bm - 8.3143 * T2 / P3;
pr_z1 = am / P3 - 3 * bm ^ 2 - 2 * bm * 8.3143 * T2 / P3;
pr_z2 = bm ^ 3 + bm ^ 2 * 8.3143 * T2 / P3 - am * bm / P3;
q = -1 * (3 * pr_z1 - pr_c1 ^ 2) / 9;
r = -1 * (9 * pr_c1 * pr_z1 - 27 * pr_z2 - 2 * pr_c1 ^ 3) / 54;
D = r ^ 2 - q ^ 3;
//Discriminant: D < 0, all 3 roots are real and unequal; D = 0, all roots are real and at least two are equal
//D > 0, only one root is real and two are imaginary
// Calculate the first root
If( D < 0,
radian = ArcCosine( r / Sqrt( q ^ 3 ) );
x1 = -1 * (2 * Sqrt( q ) * Cos( (1 / 3) * radian )) - (1 / 3) * pr_c1;
x2 = -1 * (2 * Sqrt( q ) * Cos( (radian + 2 * Pi()) / 3 )) - (1 / 3) * pr_c1;
x3 = -1 * (2 * Sqrt( q ) * Cos( (radian - 2 * Pi()) / 3 )) - (1 / 3) * pr_c1;
v = x2;
,
Sprime = -1 * (r / Abs( r )) * (Abs( r ) + Sqrt( D )) ^ (1 / 3);
Tprime = q / Sprime;
x1 = Sprime + Tprime - (1 / 3) * pr_c1;
v = x1;
);
den = (1 / v) * Mw;
Return( den );
);과거에는 이러한 계산이 VBA UDF를 사용하여 Excel에서 수행되었습니다. JMP에 대해 더 많이 알게 되면서 Excel에 대한 의존도를 줄이기 위해 JSL 코드를 사용하여 JMP를 다시 구현하기 시작했습니다.하지만 여기서는 JMP 기능의 한계에 도달하기 시작했고 아마도 JMP에서 이러한 종류의 일을 할 수 없을 것 같습니다.또는 최소한 배열 조회 및 사용자 정의 기능을 사용할 때 더 작은 데이터 세트로 작업해야 합니다.
JSL이 좋아보입니다. 그러나 나는 열 수식에서 많은 지역 변수와 조회 함수를 사용하는 복잡한 계산을 거의 사용하지 않습니다. 테이블 외부에서 코드를 실행하여 (새) 행을 채우는 것이 아마도 더 효율적일 것입니다. 이렇게 하면 행렬 연산을 사용하여 계산을 더 쉽게 "병렬화"할 수 있습니다.
열 수식이 필요한 경우 전체 테이블의 재계산을 방지하는 한 가지 방법은 기본 테이블의 1행 하위 집합에 새 데이터를 추가하고, 수식을 평가하고, 수식 평가를 억제하고, 첫 번째 행을 삭제(중복 방지를 위해)하는 것입니다. 업데이트된 하위 집합을 기본 테이블과 연결합니다(수식 평가가 억제됨).
연관 배열은 여기에서 병목 현상이 될 수 있습니다. 배열을 살펴보는 대신 데이터 테이블의 다른 열에서 각 행에 대해 이러한 메타데이터를 검색할 수 있다면 수식이 더 빨리 실행될 것이라고 생각합니다.