From 6cb40633dea1d5adb0f2d904690f24ca30561940 Mon Sep 17 00:00:00 2001 From: Romain Bazile Date: Wed, 6 Jan 2021 13:27:07 +0100 Subject: [PATCH] ui: calculate theorical volume for net, fix metadata export --- flows/main.json | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/flows/main.json b/flows/main.json index 3eac6b7..5357df6 100644 --- a/flows/main.json +++ b/flows/main.json @@ -2168,7 +2168,8 @@ "wires": [ [ "726a7822.cd6298", - "e2b277c1.07283" + "e2b277c1.07283", + "9a18a4b4.178448" ], [ "52f6b103.1efb6" @@ -3346,8 +3347,7 @@ [ "20e0a8c8.edbeb" ] - ], - "info": "### Focusing\n##### focus.py `nb_step` `orientation`\n\n- `nb_step` : **integer** (from 1 to 100000) - number of step to perform by the stage (about 31um/step)\n- `orientation` : **string** - orientation of the focus either `up` or `down`\n\nExample:\n\n python3.7 $HOME/PlanktonScope/scripts/focus.py 650 up\n" + ] }, { "id": "20e0a8c8.edbeb", @@ -3457,7 +3457,7 @@ "type": "function", "z": "baa1e3d9.cb29d", "name": "Encapsulate config", - "func": "msg.payload = {\n\t\"action\": \"update_config\",\n\t\"config\": {\n \t\"description\": {\n \t\t\"sample_project\": \"Project's name\",\n \t\t\"sample_id\": \"Sample ID\",\n \t\t\"sample_uuid\": \"Sample UUID (Autogenerated)\",\n \t\t\"sample_ship\": \"Ship's name\",\n \t\t\"sample_operator\": \"Operator's name\",\n \t\t\"sample_sampling_gear\": \"Sampling gear used\",\n \t\t\"sample_concentrated_sample_volume\": \"Volume of concentrated sample, in mL\",\n \t\t\"sample_total_volume\": \"Total volume filtered by the net used, in L\",\n \t\t\"acq_id\": \"Acquisition ID\",\n \t\t\"acq_uuid\": \"Acquisition UUID (Autogenerated)\",\n \t\t\"acq_instrument\": \"Instrument type\",\n \t\t\"acq_instrument_id\": \"Instrument ID\",\n \t\t\"acq_celltype\": \"Flow cell dimension thickness, in µm\",\n \t\t\"acq_minimum_mesh\": \"Minimum filtration mesh size, in µm\",\n \t\t\"acq_maximum_mesh\": \"Maximum filtration mesh size, in µm\",\n \t\t\"acq_min_esd\": \"\",\n \t\t\"acq_max_esd\": \"\",\n \t\t\"acq_volume\": \"Imaged volume, in mL\",\n \t\t\"acq_magnification\": \"Optical magnification\",\n \t\t\"acq_fnumber_objective\": \"Focal length of the objective, in mm\",\n \t\t\"acq_camera_name\": \"Name of the camera used\",\n \t\t\"acq_nb_frame\": \"Number of picture taken\",\n \"acq_local_datetime\": \"Instrument local datetime\",\n \"acq_camera_resolution\": \"Resolution of the images\",\n \"acq_camera_iso\": \"ISO Number of the images\",\n \"acq_camera_shutter_speed\": \"Shutter speed of the images, in µs\",\n \"acq_software\": \"Software version number\",\n \t\t\"object_date\": \"Sample collection date (or beginning if using a net)\",\n \t\t\"object_time\": \"Sample collection time (or beginning if using a net)\",\n \t\t\"object_lat\": \"Sample collection latitude (or beginning if using a net)\",\n \t\t\"object_lon\": \"Sample collection longitude (or beginning if using a net)\",\n \t\t\"object_depth_min\": \"Sample collection minimal depth, in m\",\n \t\t\"object_depth_max\": \"Sample collection maximum depth, in m\",\n \t\t\"process_pixel\": \"Pixel imaging resolution, in µm/pixel\",\n \t\t\"process_id\": \"Segmentation ID\",\n \t\t\"process_uuid\": \"Segmentation UUID (Autogenerated)\",\n \t\t\"sample_gear_net_opening\": \"Sample mouth opening dimension, in mm\",\n \t\t\"object_date_end\": \"Sample end collection date when using a net\",\n \t\t\"object_time_end\": \"Sample end collection time when using a net\",\n \t\t\"object_lat_end\": \"Sample end collection latitude when using a net\",\n \t\t\"object_lon_end\": \"Sample end collection longitude when using a net\",\n \t},\n\t\t\"sample_project\": global.get(\"sample_project\"),\n\t\t\"sample_id\": global.get(\"sample_id\"),\n\t\t\"sample_ship\": global.get(\"sample_ship\"),\n\t\t\"sample_operator\": global.get(\"sample_operator\"),\n\t\t\"sample_sampling_gear\": global.get(\"sample_sampling_gear\"),\n\t\t\"sample_concentrated_sample_volume\": global.get(\"sample_concentrated_sample_volume\"),\n\n\t\t\"acq_id\": global.get(\"acq_id\"),\n\t\t\"acq_instrument\": global.get(\"acq_instrument\"),\n\t\t\"acq_instrument_id\": global.get(\"acq_instrument_id\"),\n\t\t\"acq_celltype\": global.get(\"acq_celltype\"),\n\t\t\"acq_minimum_mesh\": global.get(\"acq_minimum_mesh\"),\n\t\t\"acq_maximum_mesh\": global.get(\"acq_maximum_mesh\"),\n\t\t\"acq_min_esd\": global.get(\"acq_min_esd\"),\n\t\t\"acq_max_esd\": global.get(\"acq_max_esd\"),\n\t\t\"acq_volume\": global.get(\"acq_volume\"),\n\t\t\"acq_magnification\": global.get(\"magnification\"),\n\t\t\"acq_fnumber_objective\": global.get(\"acq_fnumber_objective\"),\n\t\t\"acq_camera\": global.get(\"acq_camera\"),\n\t\t\"acq_nb_frame\": global.get(\"nb_frame\"),\n\t\t\"acq_software\": global.get(\"acq_software\"),\n\n\t\t\"object_date\": global.get(\"object_date\"),\n\t\t\"object_time\": global.get(\"object_time\"),\n\t\t\"object_lat\": global.get(\"object_lat\"),\n\t\t\"object_lon\": global.get(\"object_lon\"),\n\t\t\"object_depth_min\": global.get(\"object_depth_min\"),\n\t\t\"object_depth_max\": global.get(\"object_depth_max\"),\n\n\t\t\"process_pixel\": global.get(\"process_pixel\"),\n\t\t\"process_id\": global.get(\"process_id\")\n\t}\n};\n\nif (msg.payload.config.sample_sampling_gear.startsWith(\"net\")) {\n\tmsg.payload.config[\"sample_gear_net_opening\"] = global.get(\"sample_gear_net_opening\")\n\tmsg.payload.config[\"object_date_end\"] = global.get(\"object_date_end\")\n\tmsg.payload.config[\"object_time_end\"] = global.get(\"object_time_end\")\n\tmsg.payload.config[\"object_lat_end\"] = global.get(\"object_lat_end\")\n\tmsg.payload.config[\"object_lon_end\"] = global.get(\"object_lon_end\")\n\t\n\tif (msg.payload.config.sample_sampling_gear == \"net_decknet\") {\n \tmsg.payload.config[\"sample_total_volume\"] = global.get(\"sample_total_volume\")\n }\n}\nreturn msg;", + "func": "msg.payload = {\n\t\"action\": \"update_config\",\n\t\"config\": {\n \t\"description\": {\n \t\t\"sample_project\": \"Project's name\",\n \t\t\"sample_id\": \"Sample ID\",\n \t\t\"sample_uuid\": \"Sample UUID (Autogenerated)\",\n \t\t\"sample_ship\": \"Ship's name\",\n \t\t\"sample_operator\": \"Operator's name\",\n \t\t\"sample_sampling_gear\": \"Sampling gear used\",\n \t\t\"sample_concentrated_sample_volume\": \"Volume of concentrated sample, in mL\",\n \t\t\"sample_total_volume\": \"Total volume filtered by the net used, in L\",\n \t\t\"acq_id\": \"Acquisition ID\",\n \t\t\"acq_uuid\": \"Acquisition UUID (Autogenerated)\",\n \t\t\"acq_instrument\": \"Instrument type\",\n \t\t\"acq_instrument_id\": \"Instrument ID\",\n \t\t\"acq_celltype\": \"Flow cell dimension thickness, in µm\",\n \t\t\"acq_minimum_mesh\": \"Minimum filtration mesh size, in µm\",\n \t\t\"acq_maximum_mesh\": \"Maximum filtration mesh size, in µm\",\n \t\t\"acq_min_esd\": \"\",\n \t\t\"acq_max_esd\": \"\",\n \t\t\"acq_volume\": \"Pumped volume, in mL\",\n\t\t \"acq_imaged_volume\": \"Total imaged volume, in mL\",\n \t\t\"acq_magnification\": \"Optical magnification\",\n \t\t\"acq_fnumber_objective\": \"Focal length of the objective, in mm\",\n \t\t\"acq_camera_name\": \"Name of the camera used\",\n \t\t\"acq_nb_frame\": \"Number of picture taken\",\n \"acq_local_datetime\": \"Instrument local datetime\",\n \"acq_camera_resolution\": \"Resolution of the images\",\n \"acq_camera_iso\": \"ISO Number of the images\",\n \"acq_camera_shutter_speed\": \"Shutter speed of the images, in µs\",\n \"acq_software\": \"Software version number\",\n \t\t\"object_date\": \"Sample collection date (or beginning if using a net)\",\n \t\t\"object_time\": \"Sample collection time (or beginning if using a net)\",\n \t\t\"object_lat\": \"Sample collection latitude (or beginning if using a net)\",\n \t\t\"object_lon\": \"Sample collection longitude (or beginning if using a net)\",\n \t\t\"object_depth_min\": \"Sample collection minimal depth, in m\",\n \t\t\"object_depth_max\": \"Sample collection maximum depth, in m\",\n \t\t\"process_pixel\": \"Pixel imaging resolution, in µm/pixel\",\n \t\t\"process_id\": \"Segmentation ID\",\n \t\t\"process_uuid\": \"Segmentation UUID (Autogenerated)\",\n \t\t\"sample_gear_net_opening\": \"Sample mouth opening dimension, in mm\",\n \t\t\"object_date_end\": \"Sample end collection date when using a net\",\n \t\t\"object_time_end\": \"Sample end collection time when using a net\",\n \t\t\"object_lat_end\": \"Sample end collection latitude when using a net\",\n \t\t\"object_lon_end\": \"Sample end collection longitude when using a net\",\n \t},\n\t\t\"sample_project\": global.get(\"sample_project\"),\n\t\t\"sample_id\": global.get(\"sample_project\") + \"_\" + global.get(\"sample_id\"),\n\t\t\"sample_ship\": global.get(\"sample_ship\"),\n\t\t\"sample_operator\": global.get(\"sample_operator\"),\n\t\t\"sample_sampling_gear\": global.get(\"sample_sampling_gear\"),\n\t\t\"sample_concentrated_sample_volume\": global.get(\"sample_concentrated_sample_volume\"),\n\n\t\t\"acq_id\": global.get(\"sample_project\") + \"_\" + global.get(\"sample_id\")+ \"_\" + global.get(\"acq_id\"),\n\t\t\"acq_instrument\": global.get(\"acq_instrument\"),\n\t\t\"acq_instrument_id\": global.get(\"acq_instrument_id\"),\n\t\t\"acq_celltype\": global.get(\"acq_celltype\"),\n\t\t\"acq_minimum_mesh\": global.get(\"acq_minimum_mesh\"),\n\t\t\"acq_maximum_mesh\": global.get(\"acq_maximum_mesh\"),\n\t\t\"acq_min_esd\": global.get(\"acq_min_esd\"),\n\t\t\"acq_max_esd\": global.get(\"acq_max_esd\"),\n\t\t\"acq_volume\": global.get(\"acq_volume\"),\n\t\t\"acq_imaged_volume\": global.get(\"acq_imaged_volume\"),\n\t\t\"acq_magnification\": global.get(\"magnification\"),\n\t\t\"acq_fnumber_objective\": global.get(\"acq_fnumber_objective\"),\n\t\t\"acq_camera\": global.get(\"acq_camera\"),\n\t\t\"acq_nb_frame\": global.get(\"nb_frame\"),\n\t\t\"acq_software\": global.get(\"acq_software\"),\n\n\t\t\"object_date\": global.get(\"object_date\"),\n\t\t\"object_time\": global.get(\"object_time\"),\n\t\t\"object_lat\": global.get(\"object_lat\"),\n\t\t\"object_lon\": global.get(\"object_lon\"),\n\t\t\"object_depth_min\": global.get(\"object_depth_min\"),\n\t\t\"object_depth_max\": global.get(\"object_depth_max\"),\n\n\t\t\"process_pixel\": global.get(\"process_pixel\"),\n\t\t\"process_id\": global.get(\"process_id\")\n\t}\n};\n\nif (msg.payload.config.sample_sampling_gear.startsWith(\"net\")) {\n\tmsg.payload.config[\"sample_gear_net_opening\"] = global.get(\"sample_gear_net_opening\")\n\tmsg.payload.config[\"object_date_end\"] = global.get(\"object_date_end\")\n\tmsg.payload.config[\"object_time_end\"] = global.get(\"object_time_end\")\n\tmsg.payload.config[\"object_lat_end\"] = global.get(\"object_lat_end\")\n\tmsg.payload.config[\"object_lon_end\"] = global.get(\"object_lon_end\")\n\tmsg.payload.config[\"sample_total_volume\"] = global.get(\"sample_total_volume\")\n}\nreturn msg;", "outputs": 1, "noerr": 0, "initialize": "", @@ -8395,5 +8395,21 @@ "81a48376.27a66" ] ] + }, + { + "id": "9a18a4b4.178448", + "type": "function", + "z": "b771c342.49603", + "name": "calculate sample_total_volume", + "func": "var object_lat = global.get(\"object_lat\")\nvar object_lon = global.get(\"object_lon\")\nvar object_lat_end = global.get(\"object_lat_end\")\nvar object_lon_end = global.get(\"object_lon_end\")\nvar sample_gear_net_opening = global.get(\"sample_gear_net_opening\");\nvar sample_sampling_gear= global.get(\"sample_sampling_gear\");\n\n/*object_lat = 33.95 \nobject_lon = 118.4 \nobject_lat_end = 40.6333 \nobject_lon_end = 73.78333\nsample_gear_net_opening = 40*/\n// Copyright 1997 Ed Williams. All rights reserved\n// Adapted by Romain Bazile - Ocean Trotter - 01-2021\n\ndecpl=4 // Dec places of minutes output\n\nellipse = {\"name\":\"WSG84\", \"a\":6378.137/1.852, \"invf\":298.257223563}\n\nfunction ComputeDistance(lat1, lon1, lat2, lon2){\n var d,crs12,crs21\n var argacos\n var a,invf\n \n // lat and lon in radian\n lat1=(Math.PI/180)*lat1\n lat2=(Math.PI/180)*lat2\n lon1=(Math.PI/180)*lon1\n lon2=(Math.PI/180)*lon2\n \n //alert(\"lat1=\" + lat1 + \"lon1=\" + lon1 +\"\\nlat2=\" +lat2+ \"lon2=\"+lon2)\n \n /* get distance conversion factor */\n dc=1.852 //km\n //alert(\"dc=\" +dc)\n \n //showProps(ellipse,\"ellipse\")\n \n // elliptic code\n d=crsdist_ell(lat1,-lon1,lat2,-lon2,ellipse) // ellipse uses East negative\n d=d*dc // go to physical units\n \n //alert(\"d=\"+d+\" crs12=\"+crs12+\" crs21=\"+crs21)\n return d\n}\n\nfunction crsdist(lat1,lon1,lat2,lon2){ // radian args\n /* compute course and distance (spherical) */\n if ((lat1+lat2===0) && (Math.abs(lon1-lon2)==Math.PI) && \n (Math.abs(lat1) != (Math.PI/180)*90)){\t\n \talert(\"Course between antipodal points is undefined\")\n }\n \n d = Math.acos(Math.sin(lat1)*Math.sin(lat2)+Math.cos(lat1)*Math.cos(lat2)*Math.cos(lon1-lon2))\n return d\n}\n\nfunction crsdist_ell(glat1,glon1,glat2,glon2,ellipse){\n // glat1 initial geodetic latitude in radians N positive \n // glon1 initial geodetic longitude in radians E positive \n // glat2 final geodetic latitude in radians N positive \n // glon2 final geodetic longitude in radians E positive \n a=ellipse.a\n f=1/ellipse.invf\n //alert(\"a=\"+a+\" f=\"+f)\n var r, tu1, tu2, cu1, su1, cu2, s1, b1, f1\n var x, sx, cx, sy, cy,y, sa, c2a, cz, e, c, d\n var EPS= 0.00000000005\n var faz, baz, s\n var iter=1\n var MAXITER=100\n if ((glat1+glat2===0) && (Math.abs(glon1-glon2)==Math.PI)){\n alert(\"Course and distance between antipodal points is undefined\")\n glat1=glat1+0.00001 // allow algorithm to complete\n }\n if (glat1==glat2 && (glon1==glon2 || Math.abs(Math.abs(glon1-glon2)-2*Math.PI) < EPS)){\n alert(\"Points 1 and 2 are identical- course undefined\")\n out=new MakeArray(0)\n out.d=0\n out.crs12=0\n out.crs21=Math.PI\n return out\n }\n r = 1 - f\n tu1 = r * Math.tan (glat1)\n tu2 = r * Math.tan (glat2)\n cu1 = 1 / Math.sqrt (1 + tu1 * tu1)\n su1 = cu1 * tu1\n cu2 = 1 / Math.sqrt (1 + tu2 * tu2)\n s1 = cu1 * cu2\n b1 = s1 * tu2\n f1 = b1 * tu1\n x = glon2 - glon1\n d = x + 1 // force one pass\n while ((Math.abs(d - x) > EPS) && (iter < MAXITER))\n {\n iter=iter+1\n sx = Math.sin (x)\n // alert(\"sx=\"+sx)\n cx = Math.cos (x)\n tu1 = cu2 * sx\n tu2 = b1 - su1 * cu2 * cx\n sy = Math.sqrt(tu1 * tu1 + tu2 * tu2)\n cy = s1 * cx + f1\n y = atan2 (sy, cy)\n sa = s1 * sx / sy\n c2a = 1 - sa * sa\n cz = f1 + f1\n if (c2a > 0)\n cz = cy - cz / c2a\n e = cz * cz * 2 - 1\n c = ((-3 * c2a + 4) * f + 4) * c2a * f / 16\n d = x\n x = ((e * cy * c + cz) * sy * c + y) * sa\n x = (1 - c) * x * f + glon2 - glon1\n }\n x = Math.sqrt ((1 / (r * r) - 1) * c2a + 1)\n x +=1\n x = (x - 2) / x\n c = 1 - x\n c = (x * x / 4 + 1) / c\n d = (0.375 * x * x - 1) * x\n x = e * cy\n d = ((((sy*sy*4-3)*(1-e-e)*cz*d/6-x)*d/4+cz)*sy*d+y)*c*a*r\n if (Math.abs(iter-MAXITER)0) && (y>=0)){ out= Math.atan(y/x)}\n if ((x >0) && (y<0)) { out= Math.atan(y/x)+2*Math.PI}\n if ((x===0) && (y>0)) { out= Math.PI/2}\n if ((x===0) && (y<0)) { out= 3*Math.PI/2} \n if ((x===0) && (y===0)) {\n alert(\"atan2(0,0) undefined\")\n out= 0\n } \n return out\n}\n\nfunction showProps(obj,objName){\n var result=\"\"\n for (var i in obj){\n result +=objName + \".\" + i + \" = \" + obj[i] + \"\\n\"\n }\n alert(result)\n}\n\nif (sample_sampling_gear.startsWith(\"net\") && sample_sampling_gear != \"net_decknet\"){\n distance_km = ComputeDistance(object_lat, object_lon, object_lat_end, object_lon_end)\n \n sample_total_volume = distance_km*(Math.PI*(sample_gear_net_opening/2)*(sample_gear_net_opening/2))/1000// cubic meter\n sample_total_volume = Math.round((sample_total_volume + Number.EPSILON) * 1000) / 1000\n global.set(\"sample_total_volume\", sample_total_volume)\n msg.payload = sample_total_volume\n}\nelse {\n msg.payload = 0\n}\n\n\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "x": 770, + "y": 580, + "wires": [ + [] + ] } ] \ No newline at end of file