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 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 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 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 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 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> posEdgePts; List> negEdgePts; if (imageFlag == 1) { var result = extractEdgeCoordinate( imageFilePath, outputFileName, syringeWidth, ); posEdgePts = result[0]; negEdgePts = result[1]; double deScaledMaxWidth = result[2]; List dmsDiameters = List.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 positiveLines = File(posPointsFileName).readAsLinesSync(); for (var Line in positiveLines) { List 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 negativeLines = File(negPointsFileName).readAsLinesSync(); for (var Line in negativeLines) { List 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 bruteForce() { List> posList = []; List> negList = []; for (int processNo = 0; processNo < processCount; processNo++) { posList.add(posEdgePts); negList.add(negEdgePts); //print(processNo); } List> 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> bestParams = []; // will store candidate tuples List 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 bestOutput = [999999999, 1, 1, 1, 1]; for (var output in bestParams) { if (output[0] < bestOutput[0]) { bestOutput = output; } } return bestOutput; } // Nested function Optimize List 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 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"); }