362 lines
11 KiB
Dart
362 lines
11 KiB
Dart
import 'dart:io';
|
|
import 'dart:math';
|
|
import 'package:scidart/scidart.dart';
|
|
|
|
import 'extract_edge_coordinate.dart';
|
|
import 'find_optimal_params_bashforthadams.dart';
|
|
import 'juszas_equation.dart';
|
|
import 'minimize_params_optimization.dart';
|
|
|
|
void computeST(List<String> sysArgs) {
|
|
// Initial variable definitions
|
|
String imageFilePath = "";
|
|
String outputFileName = "";
|
|
String posPointsFileName = "";
|
|
String negPointsFileName = "";
|
|
int processCount = 2;
|
|
double syringeWidth = 0.70 * 1.15;
|
|
double minaRadcurv = 0.0001;
|
|
double maxaRadcurv = 2.0001;
|
|
double minbShapefact = 0.0001;
|
|
double maxbShapefact = 1.0001;
|
|
double minX = 0.0001;
|
|
double maxX = 0.5001;
|
|
double mintAngle = 0.0001;
|
|
double maxtAngle = 0.5001;
|
|
int aStep = 20;
|
|
int bStep = 20;
|
|
int xStep = 5;
|
|
int tStep = 5;
|
|
|
|
int imageFlag = 0;
|
|
int posFileFlag = 0;
|
|
int negFileFlag = 0;
|
|
int outFlag = 0;
|
|
int counter = 0;
|
|
int solveMethod = 0;
|
|
|
|
// Argument processing loop.
|
|
while (counter <= sysArgs.length - 1) {
|
|
String currentOption = sysArgs[counter];
|
|
String currentValue = "";
|
|
try {
|
|
currentValue = sysArgs[counter + 1];
|
|
} catch (e) {
|
|
exit(0);
|
|
}
|
|
|
|
if (currentOption == "-help") {
|
|
exit(0);
|
|
} else if (currentOption == "-img") {
|
|
imageFilePath = currentValue;
|
|
imageFlag = 1;
|
|
} else if (currentOption == "-filep") {
|
|
posPointsFileName = currentValue;
|
|
posFileFlag = 1;
|
|
} else if (currentOption == "-filen") {
|
|
negPointsFileName = currentValue;
|
|
negFileFlag = 1;
|
|
} else if (currentOption == "-out") {
|
|
outputFileName = currentValue;
|
|
outFlag = 1;
|
|
} else if (currentOption == "-proc") {
|
|
processCount = int.parse(currentValue);
|
|
} else if (currentOption == "-syrg") {
|
|
syringeWidth = double.parse(currentValue);
|
|
} else if (currentOption == "-a") {
|
|
minaRadcurv = double.parse(currentValue);
|
|
} else if (currentOption == "-A") {
|
|
maxaRadcurv = double.parse(currentValue);
|
|
} else if (currentOption == "-b") {
|
|
minbShapefact = double.parse(currentValue);
|
|
} else if (currentOption == "-B") {
|
|
maxbShapefact = double.parse(currentValue);
|
|
} else if (currentOption == "-x") {
|
|
minX = double.parse(currentValue);
|
|
} else if (currentOption == "-X") {
|
|
maxX = double.parse(currentValue);
|
|
} else if (currentOption == "-t") {
|
|
mintAngle = double.parse(currentValue);
|
|
} else if (currentOption == "-T") {
|
|
maxtAngle = double.parse(currentValue);
|
|
} else if (currentOption == "-ai") {
|
|
aStep = int.parse(currentValue);
|
|
} else if (currentOption == "-bi") {
|
|
bStep = int.parse(currentValue);
|
|
} else if (currentOption == "-xi") {
|
|
xStep = int.parse(currentValue);
|
|
} else if (currentOption == "-ti") {
|
|
tStep = int.parse(currentValue);
|
|
} else if (currentOption == "-solver") {
|
|
solveMethod = int.parse(currentValue);
|
|
} else {
|
|
exit(0);
|
|
}
|
|
counter = counter + 2;
|
|
}
|
|
|
|
if (outFlag == 0 && imageFlag == 1) {
|
|
print("Output file name not set. (-out)");
|
|
exit(0);
|
|
}
|
|
if (imageFlag == 1 && ((posFileFlag == 1) || (negFileFlag == 1))) {
|
|
print("Image(-img) can not be set with files option (-filep, -filen).");
|
|
print("Either set image only or files only.");
|
|
exit(0);
|
|
}
|
|
if (imageFlag == 0 &&
|
|
((posFileFlag == 1 && negFileFlag == 0) ||
|
|
(posFileFlag == 0 && negFileFlag == 1))) {
|
|
print(
|
|
"File inputs (-filep, -filen) should both be set if image input is not set.",
|
|
);
|
|
exit(0);
|
|
}
|
|
|
|
// Calculate ARange_radCurv
|
|
List<double> ARange_radCurv = [];
|
|
double a = minaRadcurv;
|
|
double ahop = (maxaRadcurv - minaRadcurv) / (aStep - 1);
|
|
while (a <= maxaRadcurv) {
|
|
ARange_radCurv.add(a);
|
|
a += ahop;
|
|
if (ahop == 0.0) {
|
|
break;
|
|
}
|
|
}
|
|
if ((maxaRadcurv - ARange_radCurv[ARange_radCurv.length - 1] - ahop).abs() <
|
|
0.000001 &&
|
|
ahop != 0.0) {
|
|
ARange_radCurv.add(maxaRadcurv);
|
|
}
|
|
|
|
// Calculate bRange_shapeFact
|
|
List<double> brangeShapefact = [];
|
|
double b = minbShapefact;
|
|
double bhop = (maxbShapefact - minbShapefact) / (bStep - 1);
|
|
while (b <= maxbShapefact) {
|
|
brangeShapefact.add(b);
|
|
b += bhop;
|
|
if (bhop == 0) {
|
|
break;
|
|
}
|
|
}
|
|
if ((maxbShapefact - brangeShapefact[brangeShapefact.length - 1] - bhop)
|
|
.abs() <
|
|
0.000001 &&
|
|
bhop != 0.0) {
|
|
brangeShapefact.add(maxbShapefact);
|
|
}
|
|
|
|
// Calculate XRange
|
|
List<double> XRange = [];
|
|
double x = minX;
|
|
double xhop = (maxX - minX) / (xStep - 1);
|
|
while (x <= maxX) {
|
|
XRange.add(x);
|
|
x += xhop;
|
|
if (xhop == 0) {
|
|
break;
|
|
}
|
|
}
|
|
if ((maxX - XRange[XRange.length - 1] - xhop).abs() < 0.000001 &&
|
|
xhop != 0.0) {
|
|
XRange.add(maxX);
|
|
}
|
|
|
|
// Calculate TRange_angle
|
|
List<double> TRange_angle = [];
|
|
double t = mintAngle;
|
|
double thop = (maxtAngle - mintAngle) / (tStep - 1);
|
|
while (t <= maxtAngle) {
|
|
TRange_angle.add(t);
|
|
t += thop;
|
|
if (thop == 0.0) {
|
|
break;
|
|
}
|
|
}
|
|
if ((maxtAngle - TRange_angle[TRange_angle.length - 1] - thop).abs() <
|
|
0.000001 &&
|
|
thop != 0.0) {
|
|
TRange_angle.add(maxtAngle);
|
|
}
|
|
|
|
print("\n");
|
|
if (imageFlag == 1) {
|
|
print("Image File : $imageFilePath");
|
|
print("Output Name : $outputFileName");
|
|
print("Negative Coordinate File : ${outputFileName}_Negative.dat");
|
|
print("Positive Coordinate File : ${outputFileName}_Positive.dat");
|
|
print("Syringe Width (millimeter): $syringeWidth");
|
|
} else {
|
|
print("Negative Coordinate File : $negPointsFileName");
|
|
print("Positive Coordinate File : $posPointsFileName");
|
|
}
|
|
print(
|
|
"Radius of Curvature Range : $minaRadcurv-$maxaRadcurv (interval: ${ARange_radCurv.length})",
|
|
);
|
|
print(
|
|
"Shape Factor Range : $minbShapefact-$maxbShapefact (interval: ${brangeShapefact.length})",
|
|
);
|
|
print("Initial X Coordinate Range: $minX-$maxX (interval: ${XRange.length})");
|
|
print(
|
|
"Initial Angle Range : $mintAngle-$maxtAngle (interval: ${TRange_angle.length})",
|
|
);
|
|
print(
|
|
"Parameter Combinations : ${ARange_radCurv.length * brangeShapefact.length * XRange.length * TRange_angle.length}",
|
|
);
|
|
print("Number of Process to Use : $processCount");
|
|
|
|
List<List<double>> posEdgePts;
|
|
List<List<double>> negEdgePts;
|
|
|
|
if (imageFlag == 1) {
|
|
var result = extractEdgeCoordinate(
|
|
imageFilePath,
|
|
outputFileName,
|
|
syringeWidth,
|
|
);
|
|
posEdgePts = result[0];
|
|
negEdgePts = result[1];
|
|
double deScaledMaxWidth = result[2];
|
|
List<double> dmsDiameters = List<double>.from(result[3]);
|
|
|
|
double HInv1 = HJuza(dmsDiameters[7] / deScaledMaxWidth, 0.8);
|
|
double HInv2 = HJuza(dmsDiameters[8] / deScaledMaxWidth, 0.9);
|
|
double HInv3 = HJuza(dmsDiameters[9] / deScaledMaxWidth, 1.0);
|
|
double HInv4 = HJuza(dmsDiameters[10] / deScaledMaxWidth, 1.1);
|
|
double HInv5 = HJuza(dmsDiameters[11] / deScaledMaxWidth, 1.2);
|
|
double HInvM = (0.20) * (HInv1 + HInv2 + HInv3 + HInv4 + HInv5);
|
|
double HInvSD = sqrt(
|
|
(0.20) *
|
|
((HInv1 - HInvM) * (HInv1 - HInvM) +
|
|
(HInv2 - HInvM) * (HInv2 - HInvM) +
|
|
(HInv3 - HInvM) * (HInv3 - HInvM) +
|
|
(HInv4 - HInvM) * (HInv4 - HInvM) +
|
|
(HInv5 - HInvM) * (HInv5 - HInvM)),
|
|
);
|
|
print("Juza 5-Plane (1/H) Std.Dev: $HInvSD");
|
|
} else {
|
|
posEdgePts = [];
|
|
try {
|
|
List<String> positiveLines = File(posPointsFileName).readAsLinesSync();
|
|
for (var Line in positiveLines) {
|
|
List<String> coordinate = Line.split(RegExp(r'\s+'));
|
|
//print(coordinate);
|
|
posEdgePts.add([
|
|
double.parse(coordinate[0]),
|
|
double.parse(coordinate[1]),
|
|
]);
|
|
}
|
|
} catch (e) {
|
|
print("Error reading positive points file.");
|
|
exit(0);
|
|
}
|
|
negEdgePts = [];
|
|
try {
|
|
List<String> negativeLines = File(negPointsFileName).readAsLinesSync();
|
|
for (var Line in negativeLines) {
|
|
List<String> coordinate = Line.split(RegExp(r'\s+'));
|
|
//print(Coordinate);
|
|
negEdgePts.add([
|
|
double.parse(coordinate[0]),
|
|
double.parse(coordinate[1]),
|
|
]);
|
|
}
|
|
} catch (e) {
|
|
print("Error reading negative points file.");
|
|
exit(0);
|
|
}
|
|
}
|
|
|
|
// Nested function bruteForce
|
|
List<dynamic> bruteForce() {
|
|
List<List<double>> posList = [];
|
|
List<List<double>> negList = [];
|
|
for (int processNo = 0; processNo < processCount; processNo++) {
|
|
posList.add(posEdgePts);
|
|
negList.add(negEdgePts);
|
|
//print(processNo);
|
|
}
|
|
|
|
List<List<double>> aRanges = [];
|
|
for (int processNo = 0; processNo < processCount; processNo++) {
|
|
aRanges.add([]);
|
|
}
|
|
|
|
int i = 0;
|
|
for (var A in ARange_radCurv) {
|
|
aRanges[i % processCount].add(A);
|
|
i += 1;
|
|
}
|
|
|
|
List<List<dynamic>> bestParams = []; // will store candidate tuples
|
|
List<int> ticksQueue = []; // simulate ticks
|
|
|
|
// Simulate process creation and execution.
|
|
for (int processNo = 0; processNo < processCount; processNo++) {
|
|
// In a real multiprocessing environment, each process would run concurrently.
|
|
// Here, we directly call the function.
|
|
findOptimalParameters(
|
|
posList[processNo],
|
|
negList[processNo],
|
|
aRanges[processNo],
|
|
brangeShapefact,
|
|
XRange,
|
|
TRange_angle,
|
|
bestParams,
|
|
ticksQueue,
|
|
);
|
|
}
|
|
|
|
stdout.write("\rParameter Search Progress : 0%");
|
|
stdout.flush();
|
|
int count = 0;
|
|
int totalTicks = ARange_radCurv.length;
|
|
// Simulate receiving ticks.
|
|
while (count < totalTicks) {
|
|
// Since ticks have been already added, just increment Count.
|
|
if (ticksQueue.isNotEmpty) {
|
|
ticksQueue.removeAt(0);
|
|
count += 1;
|
|
stdout.write(
|
|
"\rParameter Search Progress : ${(100 * (count / totalTicks)).toInt()}%",
|
|
);
|
|
stdout.flush();
|
|
}
|
|
}
|
|
print("");
|
|
|
|
List<dynamic> bestOutput = [999999999, 1, 1, 1, 1];
|
|
for (var output in bestParams) {
|
|
if (output[0] < bestOutput[0]) {
|
|
bestOutput = output;
|
|
}
|
|
}
|
|
return bestOutput;
|
|
}
|
|
|
|
// Nested function Optimize
|
|
List<dynamic> optimize() {
|
|
return optimizeParameters(posEdgePts, negEdgePts, 0.95, 0.3, 0.1, 0.2);
|
|
}
|
|
|
|
// Record start time
|
|
var startTime = DateTime.now();
|
|
|
|
// Choose which solver to use.
|
|
List<dynamic> bestOutput = (solveMethod != 1) ? optimize() : bruteForce();
|
|
|
|
print("best output: $bestOutput");
|
|
|
|
print("\nLowest RMSD : ${bestOutput[0]}");
|
|
// Computed Surface Tension: 9.8*bestOutput[1]/bestOutput[2]
|
|
print("Computed Surface Tension : ${9.8 * bestOutput[1] / bestOutput[2]}");
|
|
print("Best Radius of Curvature : ${bestOutput[1]}");
|
|
print("Best Shape Factor : ${bestOutput[2]}");
|
|
print("Best Initial X Coordinate : ${bestOutput[3]}");
|
|
print("Best Initial Angle : ${bestOutput[4]}");
|
|
var elapsed = DateTime.now().difference(startTime).inSeconds;
|
|
print("Lapsed Time in Seconds : $elapsed");
|
|
}
|