Skip to content
Snippets Groups Projects
Select Git revision
  • d368e2eb1d006cb15eafb3d06d3d8ccfb65bb5d9
  • master default protected
  • hierarchical-basis
  • alphashapes
  • bl
  • relaying
  • new_export_boris
  • oras_vs_osm
  • reassign_partitions
  • distributed_fwi
  • rename-classes
  • fix/fortran-api-example-t4
  • robust_partitions
  • reducing_files
  • fix_overlaps
  • 3115-issue-fix
  • 3023-Fillet2D-Update
  • convert_fdivs
  • tmp_jcjc24
  • fixedMeshIF
  • save_edges
  • gmsh_4_14_0
  • gmsh_4_13_1
  • gmsh_4_13_0
  • gmsh_4_12_2
  • gmsh_4_12_1
  • gmsh_4_12_0
  • gmsh_4_11_1
  • gmsh_4_11_0
  • gmsh_4_10_5
  • gmsh_4_10_4
  • gmsh_4_10_3
  • gmsh_4_10_2
  • gmsh_4_10_1
  • gmsh_4_10_0
  • gmsh_4_9_5
  • gmsh_4_9_4
  • gmsh_4_9_3
  • gmsh_4_9_2
  • gmsh_4_9_1
  • gmsh_4_9_0
41 results

t16.c

Blame
  • custom_gui.cpp 4.49 KiB
    #include <cmath>
    #include <thread>
    #include <set>
    #include "gmsh.h"
    
    // This example shows how to implement a custom user interface running
    // computationally expensive calculations in separate threads. The threads can
    // update the user interface in real-time.
    
    // flag that will be set to interrupt a calculation
    bool stop_computation = false;
    
    // a computationally expensive routine, that will be run in its own thread
    void compute(const std::string &arg)
    {
      std::vector<double> iterations, progress;
      gmsh::onelab::getNumber("My App/Iterations", iterations);
      gmsh::onelab::getNumber("My App/Show progress?", progress);
      int n = iterations.size() ? static_cast<int>(iterations[0]) : 1;
      bool show = (progress.size() && progress[0]) ? true : false;
      int p = 0;
      double k = 0., last_refresh = 0.;
      for(int j = 0; j < n; j++) {
        // stop computation if requested by clicking on "Stop it!"
        if(stop_computation) break;
        k = sin(k) + cos(j / 45.);
        // show progress in real time?
        if(show && n > 1 && !(j % (n / 100))) {
          p++;
          gmsh::onelab::setString(arg, {std::to_string(p) + "%"});
          // any code in a thread other than the main thread that modifies the user
          // interface should be locked
          gmsh::fltk::lock();
          gmsh::logger::write(arg + " progress " + std::to_string(p) + "%");
          gmsh::fltk::unlock();
          // ask the main thread to process pending events and to update the user
          // interface, maximum 10 times per second
          if(gmsh::logger::getWallTime() - last_refresh > 0.1) {
            last_refresh = gmsh::logger::getWallTime();
            gmsh::fltk::awake("update");
          }
        }
      }
      gmsh::onelab::setNumber(arg + " result", {k});
      gmsh::onelab::setString("ONELAB/Action", {"done computing"});
      gmsh::fltk::awake("update");
    }
    
    bool checkForEvent(const std::string &parameters)
    {
      std::vector<std::string> action;
      gmsh::onelab::getString("ONELAB/Action", action);
      if(action.empty()) {
      }
      else if(action[0] == "should compute") {
        gmsh::onelab::setString("ONELAB/Action", {""});
        gmsh::onelab::setString("ONELAB/Button", {"Stop!", "should stop"});
        // force interface update (to show the new button label)
        gmsh::fltk::update();
        // start computationally intensive calculations in their own threads
        std::vector<double> v;
        gmsh::onelab::getNumber("My App/Number of threads", v);
        int n = v.size() ? static_cast<int>(v[0]) : 1;
        for(unsigned int i = 0; i < n; i++) {
          std::thread t(compute, "My App/Thread " + std::to_string(i + 1));
          t.detach();
        }
      }
      else if(action[0] == "should stop") {
        stop_computation = true;
      }
      else if(action[0] == "done computing") {
        // should not detach threads, and join them all here
        gmsh::onelab::setString("ONELAB/Action", {""});
        gmsh::onelab::setString("ONELAB/Button", {"Do it!", "should compute"});
        gmsh::fltk::update();
        stop_computation = false;
      }
      else if(action[0] == "reset") {
        // user clicked on "Reset database"
        gmsh::onelab::setString("ONELAB/Action", {""});
        gmsh::onelab::set(parameters);
        gmsh::fltk::update();
      }
      else if(action[0] == "check") {
        // could perform action here after each change in ONELAB parameters,
        // e.g. rebuild a CAD model, update other parameters, ...
      }
      return true;
    }
    
    int main(int argc, char **argv)
    {
      gmsh::initialize();
    
      // hide the standard Gmsh modules
      gmsh::option::setNumber("General.ShowModuleMenu", 0);
    
      // create some ONELAB parameters to control the number of iterations and
      // threads, the progress display and the custom ONELAB button (when pressed,
      // it will set the "ONELAB/Action" parameter to "should compute")
      std::string parameters = R"( [
        { "type":"number", "name":"My App/Iterations", "values":[1e6], "min":1e4,
          "max":1e9, "step":1e5, "attributes":{"Highlight":"AliceBlue"} },
        { "type":"number", "name":"My App/Number of threads", "values":[2],
          "choices":[1, 2, 3, 4], "attributes":{"Highlight":"AliceBlue"} },
        { "type":"number", "name":"My App/Show progress?", "values":[1],
          "choices":[0, 1] },
        { "type":"string", "name":"ONELAB/Button", "values":["Do it!", "should compute"],
          "visible":false }
      ] )";
    
      gmsh::onelab::set(parameters);
    
      // create the graphical user interface
      std::set<std::string> args(argv, argv + argc);
      if(!args.count("-nopopup")) {
        gmsh::fltk::initialize();
        // wait for events until the GUI is closed
        while(gmsh::fltk::isAvailable() && checkForEvent(parameters))
          gmsh::fltk::wait();
      }
    
      gmsh::finalize();
    
      return 0;
    }