Changeset 22894 for issm/trunk-jpl/src/m/classes/clusters/generic.js
- Timestamp:
- 07/03/18 01:05:04 (7 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
issm/trunk-jpl/src/m/classes/clusters/generic.js
r21911 r22894 1 //GENERIC class definition 2 // 3 // Usage: 4 // generic=new generic(); 1 // Execute script in strict mode 2 'use strict'; 3 /** 4 * generic - Class that allows for sending requests to server and handling response or errors 5 * 6 * Usage: 7 * generic = new generic(); 8 * 9 * Todo: 10 * Convert to ES6 class 11 */ 12 function generic() { 13 // Retrieve options and apply to properties 14 // {{{ 15 let args = Array.prototype.slice.call(arguments); 16 let options = new pairoptions(args.slice(0, args.length)); 17 18 this.url = options.getfieldvalue('url', ''); 19 this.np = options.getfieldvalue('np', 3); 20 this.codeversion = options.getfieldvalue('codeversion', 20486); 21 this.codepath = options.getfieldvalue('codepath', 'issmdir/bin'); 22 this.executionpath = options.getfieldvalue('executionpath', 'issmdir/execution'); 23 //}}} 24 25 26 // Methods 27 //{{{ 28 this.disp = function() { //{{{ 29 console.log(sprintf(' generic class echo:')); 30 console.log(sprintf(' url: %s', this.url)); 31 console.log(sprintf(' np: %i', this.np)); 32 console.log(sprintf(' codepath: %s', this.codepath)); 33 console.log(sprintf(' executionpath: %s', this.executionpath)); 34 }; //}}} 35 36 this.classname = function() { //{{{ 37 return 'generic'; 38 }; //}}} 39 40 this.checkconsistency = function(md, solution, analyses) { //{{{ 41 if (cluster.np < 1) { 42 md.checkmessage('Number of processors should be at least 1!'); 43 } 44 if (isNaN(cluster.np)) { 45 md.checkmessage('Number of processors NaN!'); 46 } 47 }; //}}} 48 49 this.BuildQueueScript = function(cluster, dirname, modelname, solution, io_gather, isvalgrind, isgprof, isdakota) { //{{{ 50 //write queuing script 51 //what is the executable being called? 52 executable = 'issm.exe'; 53 54 fid = fopen(modelname + '.queue','w'); 55 fprintf(fid, '#!%s\n', cluster.shell); 56 fprintf(fid, 'mpiexec -np %i %s/%s %s %s %s 2> %s.errlog >%s.outlog ', cluster.np, cluster.codepath, executable, EnumToString(solution), cluster.executionpath + '/' + dirname, modelname, modelname, modelname); 57 fclose(fid); 58 }; //}}} 59 60 this.UploadAndRun = function(md, fid, toolkitsstring, solutionstring, name, runtimename, successCallback, errorCallback, solveButtonId, callout, withProgressBar) { //{{{ 61 /* Local constants */ 62 let PROGRESS_BAR_ID = 'solve-progress-bar'; 63 let PROGRESS_BAR_TEXT_PERCENTAGE_ID = 'progress-bar-text-percentage'; 64 65 /* Local variables */ 66 let hasCallout = false; 67 let isProgressBarLoaded = false; 68 let progressBar = {}; 69 let progressBarTextPercentage = {}; 70 let request = {}; 71 let solveButton = $(solveButtonId); 72 let solveButtonText = !vesl.helpers.isEmptyOrUndefined(solveButton) ? solveButton.text() : ''; // Save initial solve button text 73 74 /* Local functions */ 75 // NOTE: After conversion of generic to ES6 class, these should be class methods 76 function loadProgressBar() { 77 callout.setContent('\ 78 <div class="progress-bar-wrapper">\ 79 <progress id="' + PROGRESS_BAR_ID + '" value="0" max="100"></progress>\ 80 <div class="progress-bar-text">\ 81 <span id="' + PROGRESS_BAR_TEXT_PERCENTAGE_ID + '">0</span>\ 82 <span>%</span>\ 83 </div>\ 84 </div>\ 85 '); 86 87 progressBar = $('#' + PROGRESS_BAR_ID); 88 progressBarTextPercentage = $('#' + PROGRESS_BAR_TEXT_PERCENTAGE_ID); 89 isProgressBarLoaded = true; 90 } 91 92 function setProgressBar(progress) { 93 progressBar.val(progress); 94 progressBarTextPercentage.text(progress); 95 } 96 97 // Check certain arguments 98 hasCallout = !vesl.helpers.isEmptyOrUndefined(callout); 99 100 // Check that we have a connection 101 if (!navigator.onLine) { 102 console.log('Error: no connection!'); 103 if (hasCallout) { 104 callout.set('No connection!', ''); 105 } else { 106 solveButton.text('No connection!').prop('disabled', false); 107 } 108 errorCallback(); 109 return; 110 } 111 112 // Create request 113 request = new XMLHttpRequest(); 114 request.open('POST', this.url, true); 115 116 // Set request properties 117 request.position = 0; // Keep track of current parsing position in repsonseText 118 request.timeout = 1000 * 60 * 60 * 3; // 3 hrs (in milliseconds); NOTE: This should match FastCgiServer timeout in Apache conf 119 120 request.ontimeout = function(event) { //{{{ 121 console.log('Error: timeout!'); 122 123 if (hasCallout) { 124 callout.set(vesl.ERROR_HEADER_GENERAL, '<p>Request timeout! ' + vesl.ERROR_CONTENT_TRY_AGAIN + '</p>'); 125 } else { 126 solveButton.text('Timeout!').prop('disabled', false); 127 } 128 129 errorCallback(); 130 }; //}}} 131 132 request.onerror = function(event) { //{{{ 133 console.log('Error: could not run!'); 134 135 if (hasCallout) { 136 callout.set(vesl.ERROR_HEADER_GENERAL, '<p>Something went wrong. ' + vesl.ERROR_CONTENT_TRY_AGAIN + '</p>'); 137 } else { 138 solveButton.text('Could not run!').prop('disabled', false); 139 } 140 141 errorCallback(); 142 }; //}}} 143 144 request.upload.onprogress = function(event) { //{{{ 145 let progress = (event.loaded / event.total * 100).toFixed(0); 146 147 if (hasCallout) { 148 callout.setHeader('Sending request...'); 149 if (withProgressBar) { 150 if (!isProgressBarLoaded) { 151 loadProgressBar(); 152 } 153 setProgressBar(progress); 154 } else { 155 callout.setContent('<p>' + progress + '%</p>'); 156 } 157 } else { 158 solveButton.text('Sending: ' + progress + '%'); 159 } 160 }; //}}} 161 162 request.onprogress = function(event) { //{{{ 163 /* Local variables */ 164 let progress = 0; 5 165 6 function generic (){ 7 //properties 8 // {{{ 9 var args = Array.prototype.slice.call(arguments); 10 var options = new pairoptions(args.slice(0,args.length)); 166 // Receive updates by parsing message length as a 32-bit hex string of form 0x*09ABCDEF)) 167 let startIndex = request.position; 168 let endIndex = request.position + 10; 169 170 if (request.responseText.length >= endIndex) { // Ensure entire hex string is loaded 171 let chunkSize = parseInt(request.responseText.slice(startIndex, endIndex)); 172 173 startIndex = endIndex; 174 endIndex = startIndex + chunkSize; 175 176 if (chunkSize >= 1024) { // Arbitrary maximium size of message (Must be below minimium size of model results) 177 progress = ((request.responseText.length - request.position) / chunkSize * 100).toFixed(0); 178 if (hasCallout) { 179 callout.setHeader('Downloading result...'); 180 if (withProgressBar) { 181 setProgressBar(progress); 182 } else { 183 callout.setContent('<p>' + progress + '%</p>'); 184 } 185 } else { 186 solveButton.text('Downloading: ' + progress + '%').prop('disabled', true); 187 } 188 } else if (request.responseText.length >= endIndex) { // Ensure entire chunk is loaded 189 progress = parseInt(request.responseText.slice(startIndex, endIndex)); 190 if (hasCallout) { 191 callout.setHeader('Computing...'); 192 if (withProgressBar) { 193 setProgressBar(progress); 194 } else { 195 callout.setContent('<p>' + progress + '%</p>'); 196 } 197 } else { 198 solveButton.text('Computing: ' + progress + '%').prop('disabled', true); 199 } 200 request.position = endIndex; 201 } 202 } 203 }; //}}} 204 205 request.onload = function(event) { //{{{ 206 /* Local variables */ 207 //{{{ 208 let buffer = {}; 209 // let bufferInflated = {}; 210 let responseText = ''; 211 //}}} 212 213 // TODO: Get context to this.str2ab or otherwise declare it in order to avoid duplication 214 function str2ab(str) { //{{{ 215 let buffer = new Uint8Array(str.length); 216 for (let i = 0, strLen = str.length; i < strLen; ++i) { 217 buffer[i] = str.charCodeAt(i); 218 } 219 return buffer; 220 } //}}} 221 222 try { 223 /* 224 console.log(request.responseText); 225 console.log('request.position : ' + request.position); 226 console.log('request.responseType : ' + request.responseType); 227 console.log('request.responseText.length : ' + request.responseText.length); 228 */ 229 responseText = window.atob(request.responseText.slice(request.position + 10).replace(/\s/g, '')); 230 // console.log('responseText.length : ' + responseText.length); 231 buffer = str2ab(responseText); 232 // console.log('buffer.length : ' + buffer.length); 233 /* 234 bufferInflated = UZIP.inflate(buffer); 235 console.log('bufferInflated.length : ' + bufferInflated.length); 236 */ 237 238 /* 239 returnBuffer = new Uint8Array(buffer); 240 returnBufferSize = returnBuffer.byteLength; 241 */ 242 243 //Write result buffer to file for debugging. Filename and MIME type are optional. 244 //writetofile(returnBuffer, 'resultBuffer', 'application/octet-stream'); 245 // md.results = parseresultsfrombuffer(md, bufferInflated, bufferInflated.length); 246 md.results = parseresultsfrombuffer(md, buffer, buffer.length); 247 248 // Let front end script handle changes to callout 249 if (hasCallout) { 250 callout.set('Success!', '<p>Solve successful</p>'); 251 } else { 252 solveButton.text(solveButtonText).prop('disabled', false); 253 } 254 successCallback(); 255 } catch (e) { 256 console.log(e); 257 if (vesl.string.startsWith(responseText, 'Error')) { 258 if (hasCallout) { 259 callout.set(vesl.ERROR_HEADER_GENERAL, '<p>Something went wrong. ' + vesl.ERROR_CONTENT_TRY_AGAIN + '</p>'); 260 } else { 261 solveButton.text('ISSM error!').prop('disabled', false); 262 } 263 } else { 264 if (hasCallout) { 265 callout.set(vesl.ERROR_HEADER_GENERAL, '<p>Something went wrong. ' + vesl.ERROR_CONTENT_TRY_AGAIN + '</p>'); 266 } else { 267 solveButton.text('JS error!').prop('disabled', false); 268 } 269 } 270 errorCallback(); 271 } 272 }; //}}} 273 274 request.responseType = 'application/octet-stream'; 275 276 /* Construct request */ 277 let npbuffer = this.str2ab(md.cluster.np.toString()); 278 npbuffer = UZIP.deflate(npbuffer); 279 let nplength = new Uint32Array(1); 280 nplength[0] = npbuffer.byteLength; 281 282 let codeversionbuffer = this.str2ab(md.cluster.codeversion.toString()); 283 codeversionbuffer = UZIP.deflate(codeversionbuffer); 284 let codeversionlength = new Uint32Array(1); 285 codeversionlength[0] = codeversionbuffer.byteLength; 286 287 let runtimenamebuffer = this.str2ab(runtimename); 288 runtimenamebuffer = UZIP.deflate(runtimenamebuffer); 289 let runtimenamelength = new Uint32Array(1); 290 runtimenamelength[0] = runtimenamebuffer.byteLength; 291 292 let namebuffer = this.str2ab(name); 293 namebuffer = UZIP.deflate(namebuffer); 294 let namelength = new Uint32Array(1); 295 namelength[0] = namebuffer.byteLength; 296 297 let toolkitsbuffer = this.str2ab(toolkitsstring); 298 toolkitsbuffer = UZIP.deflate(toolkitsbuffer); 299 let toolkitslength = new Uint32Array(1); 300 toolkitslength[0] = toolkitsbuffer.byteLength; 301 302 let solutionbuffer = this.str2ab(solutionstring); 303 solutionbuffer = UZIP.deflate(solutionbuffer); 304 let solutionlength = new Uint32Array(1); 305 solutionlength[0] = solutionbuffer.byteLength; 306 307 let binbuffer = new Uint8Array(fid.rawbuffer()); //seems that 16 bits length could be incompatible. 308 binbuffer = UZIP.deflate(binbuffer); 309 let binlength = new Uint32Array(1); 310 binlength[0] = binbuffer.byteLength; 311 312 let data = new Blob( 313 [ 314 nplength, 315 npbuffer, 316 codeversionlength, 317 codeversionbuffer, 318 runtimenamelength, 319 runtimenamebuffer, 320 namelength, 321 namebuffer, 322 toolkitslength, 323 toolkitsbuffer, 324 solutionlength, 325 solutionbuffer, 326 binlength, 327 binbuffer 328 ] 329 ); 11 330 12 this.url=options.getfieldvalue('url',''); 13 this.np=options.getfieldvalue('np',3); 14 this.codeversion=options.getfieldvalue('codeversion',20486); 15 this.codepath=options.getfieldvalue('codepath','issmdir/bin'); 16 this.executionpath=options.getfieldvalue('executionpath','issmdir/execution'); 17 //}}} 18 //methods 19 this.disp= function(){// {{{ 20 console.log(sprintf(' generic class echo:')); 21 console.log(sprintf(' url: "%s"',this.url)); 22 console.log(sprintf(' np: %i',this.np)); 23 console.log(sprintf(' codepath: "%s"',this.codepath)); 24 console.log(sprintf(' executionpath: "%s"',this.executionpath)); 25 }// }}} 26 this.classname= function(){// {{{ 27 return "generic"; 28 }// }}} 29 this.checkconsistency = function (md,solution,analyses) { //{{{ 30 if (cluster.np<1){ 31 md.checkmessage('number of processors should be at least 1'); 32 } 33 if (isNaN(cluster.np)){ 34 md.checkmessage('number of processors should not be NaN!'); 35 } 36 } //}}} 37 this.BuildQueueScript = function (cluster,dirname,modelname,solution,io_gather,isvalgrind,isgprof,isdakota) { // {{{ 38 39 //write queuing script 40 //what is the executable being called? 41 executable='issm.exe'; 42 43 fid=fopen(modelname+'.queue','w'); 44 fprintf(fid,'#!%s\n',cluster.shell); 45 fprintf(fid,'mpiexec -np %i %s/%s %s %s %s 2> %s.errlog >%s.outlog ',cluster.np,cluster.codepath,executable,EnumToString(solution),cluster.executionpath+'/'+dirname,modelname,modelname,modelname); 46 fclose(fid); 47 } //}}} 48 this.UploadAndRun = function (md,callbackfunction,callbackerrorfunction,callbackid,fid,toolkitsstring,solutionstring,name,runtimename) { //{{{ 49 if (!navigator.onLine) { //{{{ 50 $(callbackid).html(sprintf("%-16s", "NO CONNECTION")).prop("disabled", false); 51 callbackerrorfunction(); 52 return; 53 } //}}} 54 var request = new XMLHttpRequest(); 55 request.open("POST", this.url, true); 56 $(callbackid).html(sprintf("%-16s", "CONNECTING...")).prop("disabled", true); 57 request.position = 0; //Keep track of current parsing position in repsonseText 58 request.timeout = 180000; 59 request.ontimeout = function (event) { //{{{ 60 $(callbackid).html(sprintf("%-16s", "TIMEOUT")).prop("disabled", false); 61 callbackerrorfunction(); 62 } //}}} 63 request.onerror = function (event) { //{{{ 64 $(callbackid).html(sprintf("%-16s", "COULD NOT RUN")).prop("disabled", false); 65 callbackerrorfunction(); 66 } //}}} 67 request.upload.onprogress = function(event) { //{{{ 68 var progress = (event.loaded / event.total * 100).toFixed(0); 69 $(callbackid).html(sprintf("%-20s", "UPLOADING: " + progress + "%")); 70 } //}}} 71 request.onprogress = function (event) { //{{{ 72 //Receive updates by parsing message length as a 32-bit hex string of form 0x*09ABCDEF)) 73 var startIndex = request.position; 74 var endIndex = request.position + 10; 75 if (request.responseText.length >= endIndex) { //Ensure entire hex string is loaded 76 var chunkSize = parseInt(request.responseText.slice(startIndex, endIndex)); 77 startIndex = endIndex; 78 endIndex = startIndex + chunkSize; 79 if (chunkSize >= 1024) { //Arbitrary maximium size of message (Must be below minimium size of model results) 80 $(callbackid).html(sprintf("%-20s", "DOWNLOADING: " + ((request.responseText.length - request.position) / chunkSize * 100).toFixed(0) + "%")).prop("disabled", true); 81 } 82 else if (request.responseText.length >= endIndex) { //Ensure entire chunk is loaded 83 var responseChunk = request.responseText.slice(startIndex, endIndex); 84 $(callbackid).html(responseChunk); 85 request.position = endIndex; 86 } 87 } 88 }; //}}} 89 request.onload = function (event) { //{{{ 90 //get context to this.str2ab to avoid duplciation 91 function str2ab(str) { 92 var buf = new Uint8Array(str.length); 93 for (var i=0, strLen=str.length; i < strLen; i++) { 94 buf[i] = str.charCodeAt(i); 95 } 96 return buf; 97 } 98 var responseText = window.atob(request.responseText.slice(request.position + 10).replace(/\s/g, '')); 99 var buffer = pako.inflate(str2ab(responseText)); 100 var returnBuffer = new Uint8Array(buffer); 101 var returnBuffer_size = returnBuffer.byteLength; 102 try { 103 //Write result buffer to file for debugging. Filename and MIME type are optional. 104 //writetofile(returnBuffer, "resultBuffer", "application/octet-stream"); 105 md.results = parseresultsfrombuffer(md,returnBuffer,returnBuffer_size); 106 $(callbackid).html(sprintf("%-16s", "RUN")).prop("disabled", false); 107 callbackfunction(); 108 } 109 catch (e) { 110 if (responseText.startsWith('Error')) { 111 console.log(responseText); 112 $(callbackid).html(sprintf("%-16s", "ISSM ERROR")).prop("disabled", false); 113 } 114 else { 115 $(callbackid).html(sprintf("%-16s", "JS ERROR")).prop("disabled", false); 116 console.log(e); 117 } 118 callbackerrorfunction(); 119 } 120 121 }; //}}} 122 123 var npbuffer = this.str2ab(md.cluster.np.toString()); 124 npbuffer = pako.deflate(npbuffer); 125 var nplength = new Uint32Array(1); 126 nplength[0] = npbuffer.byteLength; 127 128 var codeversionbuffer = this.str2ab(md.cluster.codeversion.toString()); 129 codeversionbuffer = pako.deflate(codeversionbuffer); 130 var codeversionlength = new Uint32Array(1); 131 codeversionlength[0] = codeversionbuffer.byteLength; 132 133 var runtimenamebuffer = this.str2ab(runtimename); 134 runtimenamebuffer = pako.deflate(runtimenamebuffer); 135 var runtimenamelength = new Uint32Array(1); 136 runtimenamelength[0] = runtimenamebuffer.byteLength; 137 138 var namebuffer = this.str2ab(name); 139 namebuffer = pako.deflate(namebuffer); 140 var namelength = new Uint32Array(1); 141 namelength[0] = namebuffer.byteLength; 142 143 var toolkitsbuffer = this.str2ab(toolkitsstring); 144 toolkitsbuffer = pako.deflate(toolkitsbuffer); 145 var toolkitslength = new Uint32Array(1); 146 toolkitslength[0] = toolkitsbuffer.byteLength; 147 148 var solutionbuffer = this.str2ab(solutionstring); 149 solutionbuffer = pako.deflate(solutionbuffer); 150 var solutionlength = new Uint32Array(1); 151 solutionlength[0] = solutionbuffer.byteLength; 152 153 var binbuffer = new Uint8Array(fid.rawbuffer()); //seems that 16 bits length could be incompatible. 154 binbuffer = pako.deflate(binbuffer); 155 var binlength = new Uint32Array(1); 156 binlength[0] = binbuffer.byteLength; 157 158 var data = new Blob([nplength,npbuffer,codeversionlength,codeversionbuffer,runtimenamelength,runtimenamebuffer,namelength,namebuffer,toolkitslength,toolkitsbuffer,solutionlength,solutionbuffer,binlength,binbuffer]); 159 160 request.responseType = 'application/octet-stream'; 331 // Send request 161 332 request.send(data); 162 333 163 } //}}} 334 if (hasCallout) { 335 callout.set('Connecting...', ''); 336 } else { 337 solveButton.text('Connecting...').prop('disabled', true); 338 } 339 }; //}}} 340 164 341 this.ab2str = function(buf) { //{{{ 165 342 return String.fromCharCode.apply(null, new Uint16Array(buf)); 166 } //}}} 343 }; //}}} 344 167 345 this.str2ab = function(str) { //{{{ 168 var buf = new Uint8Array(str.length); 169 for (var i=0, strLen=str.length; i < strLen; i++) { 346 let buf = new Uint8Array(str.length); 347 348 for (let i = 0, strLen = str.length; i < strLen; i++) { 170 349 buf[i] = str.charCodeAt(i); 171 350 } 351 172 352 return buf; 173 } //}}}353 }; //}}} 174 354 }
Note:
See TracChangeset
for help on using the changeset viewer.