├── .dockerignore ├── .gitignore ├── COPYING ├── Dockerfile ├── LICENSES.md ├── README.md ├── TODO.md ├── auths ├── htpasswd │ ├── .htaccess │ ├── .htpasswd │ ├── README.md │ └── auth.php └── single-user │ └── auth.php ├── bin └── .gitignore ├── cadimporters └── upload │ ├── gmshcheck.py │ └── import_cad.php ├── cadprocessors └── gmsh │ ├── cad2stl.py │ ├── cadcheck.py │ ├── cadimport.py │ ├── initial_mesh.sh │ └── process.php ├── conf.php ├── data └── .gitignore ├── deps.sh ├── doc ├── FAQs.md ├── INSTALL.md ├── README.md ├── design.md ├── logo.svg ├── tutorials.md ├── virtual.md └── workflow.md ├── html ├── .htaccess ├── ajax2mesh.php ├── ajax2problem.php ├── ajax2yaml.php ├── assets │ └── named_cube.x3d ├── cad.php ├── case.php ├── change_step.php ├── common.php ├── css │ └── faster-than-quick ├── expert.php ├── img │ └── logo.svg ├── index.php ├── js │ ├── faster-than-quick │ └── index.html ├── mesh.php ├── mesh_data.php ├── mesh_graph.php ├── mesh_inp_save.php ├── mesh_inp_show.php ├── mesh_log.php ├── mesh_msh.php ├── meshing.php ├── meshing_cancel.php ├── meshing_relaunch.php ├── meshing_status.php ├── new │ ├── create.php │ ├── img │ │ └── logo.svg │ ├── import_cad.php │ ├── index.php │ ├── preview.php │ ├── problems.php │ ├── process.php │ └── sample.step ├── problem.php ├── problem_fee.php ├── problem_fee_save.php ├── properties.php ├── results.php ├── results_data.php ├── results_vtk.php ├── solving.php ├── solving_cancel.php ├── solving_relaunch.php └── solving_status.php ├── meshers ├── README.md └── gmsh │ ├── .gitignore │ ├── LICENSE │ ├── ajax2mesh.php │ ├── cadmesh.py │ ├── default0.geo │ ├── default1.geo │ ├── default2.geo │ ├── default3.geo │ ├── default4.geo │ ├── default5.geo │ ├── deps.sh │ ├── mesh.sh │ ├── mesh_data.cpp │ ├── mesh_data.php │ ├── mesh_data.py │ ├── mesh_graph.php │ ├── mesh_inp_save.php │ ├── mesh_inp_show.php │ ├── mesh_log.php │ ├── mesh_meta.py │ ├── mesh_status.sh │ ├── meshing_relaunch.php │ ├── meshing_status.php │ ├── process_step.php │ ├── quality.gp │ ├── quality.py │ └── trymesh.py ├── renderers └── x3dom │ ├── .gitignore │ ├── LICENSE │ └── deps.sh ├── solvers ├── README.md ├── ccx │ ├── LICENSE │ ├── ajax2problem.php │ ├── change_step_solve.php │ ├── common.php │ ├── deps.sh │ ├── frd2vtk.fee │ ├── input_initial_mechanical.php │ ├── problem_fee.php │ ├── problem_fee_save.php │ ├── problems.php │ ├── results_data.php │ ├── solve.sh │ ├── solve_status.sh │ └── solving_status.php ├── common.php ├── feenox │ ├── LICENSE │ ├── ajax2problem.php │ ├── change_step_solve.php │ ├── common.php │ ├── deps.sh │ ├── displacements.fee │ ├── feenox.xml │ ├── field.fee │ ├── field1.fee │ ├── input_initial_heat_conduction.php │ ├── input_initial_mechanical.php │ ├── problem_fee.php │ ├── problem_fee_save.php │ ├── problems.php │ ├── results_data.php │ ├── results_data │ │ ├── heat_conduction.php │ │ └── mechanical.php │ ├── second2first.fee │ ├── solve.sh │ ├── solve_status.sh │ ├── solving_relaunch.php │ └── solving_status.php ├── problems.php └── sparselizard │ ├── LICENSE │ └── problems.php └── uxs ├── .gitignore └── faster-than-quick ├── about.php ├── bootswatch ├── .gitignore ├── _bootswatch.scss ├── _variables.scss └── make.sh ├── cad.php ├── change_step.php ├── css ├── .gitignore ├── bootstrap.min.css ├── ftq.css ├── highlight.css └── index.html ├── deps.sh ├── expert.php ├── importers └── upload.php ├── index.php ├── js ├── .gitignore ├── async.js ├── ftq.js ├── heat_conduction.js ├── index.html └── mechanical.js ├── labels.php ├── labels ├── .gitignore ├── README.md ├── labels.awk ├── labels.sh └── labels.txt ├── mesh.php ├── mesh └── gmsh.php ├── meshing.php ├── named_cube.x3d ├── new.php ├── preview.php ├── problem.php ├── problem ├── heat_conduction.php └── mechanical.php ├── properties.php ├── results.php ├── results ├── heat_conduction.php └── mechanical.php ├── share.php ├── small_axes.html ├── solving.php └── ux.php /.dockerignore: -------------------------------------------------------------------------------- 1 | __pycache__ 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | deps 2 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM php:8.2.20-apache AS final 2 | RUN apt-get update && apt-get install -y \ 3 | python3 \ 4 | && rm -rf /var/lib/apt/lists/* \ 5 | RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini" 6 | COPY . /var/www 7 | RUN mkdir -p /var/www/data && chown www-data:www-data /var/www 8 | USER www-data 9 | 10 | # docker build -t suncae:2024-9-14 . 11 | # docker run -p 9000:80 suncae:2024-9-14 12 | # docker ps 13 | # docker exec -it bash 14 | -------------------------------------------------------------------------------- /LICENSES.md: -------------------------------------------------------------------------------- 1 | The SunCAE code itself is released under the terms of the [GNU Affero General Public License version 3](https://www.gnu.org/licenses/agpl-3.0.en.html), or at your option, any later version (AGPLv3+). 2 | See the [licensing details](../README.md#licensing) for more information. 3 | 4 | Here are the repositories and licenses of SunCAE third-party dependencies as shipped by the official distribution at 5 | 6 | | Type | Name | Repository | License | 7 | |:----------------|:--------------|:-------------------------------------------|:-------------:| 8 | | Renderer | X3DOM | | MIT/GPLv3+ | 9 | | UX | Bootstrap | | MIT | 10 | | CAD importer | OpenCASCADE | | LGPL-2.1 | 11 | | Mesher | Gmsh | | GPLv2+ | 12 | | Solver | FeenoX | | GPLv3+ | 13 | | Solver | CalculiX | N/A | GPLv2+ | 14 | 15 | Other dependencies (i.e. new solvers, new meshers) can be added as long as their respective licenses are respected. 16 | 17 | -------------------------------------------------------------------------------- /TODO.md: -------------------------------------------------------------------------------- 1 | 2 | # Roadmap 3 | 4 | * more problems (non-linear mechanics, transient thermal, modal, cfd, etc.) 5 | * more meshers (netgen? tetgen? salome?) 6 | * more solvers (sparselizard? fenics?) 7 | * more runners (ssh, aws, kubernetes, etc.) 8 | * more documentation 9 | 10 | # TODOs 11 | 12 | ## General 13 | 14 | * replace python with c++ to "process" msh and make it smarter 15 | * unit tests 16 | * choose units (SI, etc.) 17 | * choose points for BCs (and eventually refinements) 18 | * name in the BC should reflect the content 19 | * dashboard with case list 20 | * real-time collaboration 21 | * detect changes in CAD 22 | * git history in the UX 23 | * show face id when hovering 24 | * screenshots 25 | * once a minute refresh the axes, faces, edges, etc. (take a snapshot?) 26 | * investigate defeature operation in OCC through Gmsh (would we need a separate UX?) 27 | * re-implement how to show SunCAE version in about (when running `deps.sh`) 28 | * check that everything is fine when running `deps.sh`: 29 | - that executables work 30 | - that permissions are fine 31 | - create a `txt` with versions with `git log -1` + `git status --porcelain` 32 | * ability to take notes in markdown 33 | * help ballons, markdown + pandoc 34 | * limit DOFs: in conf? somewhere in auth? like `limits.php`? 35 | * remove visibility, everything is public 36 | 37 | 38 | ## Gmsh 39 | 40 | * STL input 41 | * combos for algorithms 42 | * checkboxes for bool 43 | * local refinements 44 | * understand failures -> train AI to come up with a proper `.geo` 45 | * other meshers! (tetget? netgen?) 46 | * multi-solid: bonded, glued, contact 47 | * curved tetrahedra 48 | * hexahedra 49 | 50 | ## Problem 51 | 52 | * choose faces with ranges e.g 1-74 53 | * other problems: modal 54 | * other solvers: ccx, sparselizard 55 | * orthotropic elasticity 56 | * thermal expansion (isotropic and orthotropic) 57 | * modal feenox 58 | * mechanical sparselizard 59 | * transient/quasistatic (a slider for time?) 60 | 61 | ## Results 62 | 63 | * fields (the list of available fields should be read from the outpt vtk/msh) 64 | - heat flux? (more general, vector fields?) 65 | * the server should tell the client 66 | - which field it is returning (so the client can choose the pallete) 67 | - if it has a warped field or not 68 | * the range scale has to be below the warp slider 69 | * nan color (yellow) 70 | * compute the .dat in the PHP, not in Bash 71 | * probes: user picks location, server returns all field 72 | * reactions: choose which BCs to compute reaction at in the problem step with a checkboxes 73 | * warning for large deformations/stresses 74 | 75 | ## Outer loops 76 | 77 | * parametric 78 | * optimization 79 | 80 | ## Dashboard 81 | 82 | * list of cases 83 | 84 | ## Backlog 85 | 86 | * zoom over mouse 87 | * disable BCs (comment them out) 88 | -------------------------------------------------------------------------------- /auths/htpasswd/.htaccess: -------------------------------------------------------------------------------- 1 | AuthType Basic 2 | AuthName "Restricted Content" 3 | AuthUserFile .htpasswd 4 | Require valid-user 5 | -------------------------------------------------------------------------------- /auths/htpasswd/.htpasswd: -------------------------------------------------------------------------------- 1 | pepe:$apr1$vATa7bcq$EBEVaET9ke0EWE6zs4P4Q1 2 | -------------------------------------------------------------------------------- /auths/htpasswd/README.md: -------------------------------------------------------------------------------- 1 | Explain how to setup httpasswd. 2 | -------------------------------------------------------------------------------- /auths/htpasswd/auth.php: -------------------------------------------------------------------------------- 1 | &1", __DIR__), $output, $error_level); 22 | 23 | // TODO: keep output 24 | if ($error_level != 0) { 25 | $response["status"] = "error"; 26 | $response["error"] = "Error {$error_level} when importing CAD: "; 27 | for ($i = 0; $i < count($output); $i++) { 28 | $response["error"] .= $output[$i]; 29 | } 30 | suncae_log("CAD {$cad_hash} process {$response["status"]} {$response["error"]}"); 31 | return_back_json($response); 32 | } 33 | } 34 | 35 | // ------------------------------------------------------------ 36 | if (file_exists("cad.json")) { 37 | $cad = json_decode(file_get_contents("cad.json"), true); 38 | $response["position"] = $cad["position"]; 39 | $response["orientation"] = $cad["orientation"]; 40 | $response["centerOfRotation"] = $cad["centerOfRotation"]; 41 | $response["fieldOfView"] = $cad["fieldOfView"]; 42 | 43 | } else { 44 | $response["status"] = "error"; 45 | $response["error"] = "Cannot create CAD json."; 46 | suncae_log("CAd {$cad_hash} process {$response["status"]} {$response["error"]}"); 47 | return_back_json($response); 48 | } 49 | 50 | 51 | // ------------------------------------------------------------ 52 | // leave running the mesher in the background 53 | exec("../../../../cadprocessors/gmsh/initial_mesh.sh > cadmesh.log 2>&1 &"); 54 | 55 | suncae_log("CAD {$cad_hash} process {$response["status"]} {$response["error"]}"); 56 | 57 | 58 | return_back_json($response); 59 | 60 | -------------------------------------------------------------------------------- /conf.php: -------------------------------------------------------------------------------- 1 | [!TIP] 4 | > If your question is not listed here, do not hesitate [contacting us](https://www.seamplex.com/suncae/#contact). 5 | 6 | ### What is the difference between SunCAE, FeenoX, Seamplex and CAEplex? 7 | 8 | * [SunCAE](https://www.seamplex.com/suncae) is an open-source web-based interface for performing CAE in the cloud. 9 | * [FeenoX](https://www.seamplex.com/feenox) is an open-source finite-element solver which used in SunCAE by default. 10 | * [Seamplex](https://www.seamplex.com) is the company that developed both SunCAE and FeenoX 11 | * [CAEplex](https://www.caeplex.com) is the first web-based interface developed by Seamplex. It is [100% integrated into Onshape](https://www.youtube.com/watch?v=ylXAUAsfb5E). 12 | 13 | 14 | ### Can I try SunCAE without having to install it? 15 | 16 | Yes, check out our [live demo](https://www.caeplex.com/suncae). 17 | Note that 18 | 19 | * There is no need to register, but your IP might get logged. 20 | * The data (including CAD files) might (or not) get lost. Do not put sensitive stuff in the demo. 21 | 22 | ### Which language is SunCAE written in? 23 | 24 | The front end is HTML with plain vanilla Javascript. This means no Angular, no React, no NodeJS, nothing. Not even JQuery. Plain vanilla Javascript (plus the Javascript libraries needed for 3D rendering). 25 | 26 | The back end is written in PHP. Again, plain PHP with at most `php-yaml` to read and write YAML files. 27 | The front end would make asynchronous AJAX calls to the back end, which would run PHP file and respond with a JSON content and so the front end can update the DOM. 28 | 29 | ### What are the licensing terms? 30 | 31 | TL;DR: if you use a modified version of SunCAE in your server, you have to provide a link to the modified sources. 32 | 33 | The content of this SunCAE repository is licensed under the terms of the [GNU Affero General Public License version 3](https://www.gnu.org/licenses/agpl-3.0.en.html), or at your option, any later version (AGPLv3+). 34 | 35 | See the [licenses table](../LICENSES.md) and [licensing details](../README.,d#licensing) for more information. 36 | 37 | 38 | ### How does SunCAE import the CAD geometry? 39 | 40 | So far, only using [OpenCASCADE](https://dev.opencascade.org) through the [Gmsh API](https://gitlab.onelab.info/gmsh/gmsh/-/tree/master/api). 41 | 42 | > [!NOTE] 43 | > If you want other CAD imported to be supported, say so in the [forum](https://github.com/seamplex/suncae/discussions). 44 | 45 | ### What are the supported meshers? 46 | 47 | So far, only [Gmsh](http://gmsh.info/) is supported. 48 | 49 | See the directory [`meshers`](https://github.com/seamplex/suncae/tree/main/meshers) for the current list. 50 | 51 | > [!NOTE] 52 | > If you want other meshers to be supported, say so in the [forum](https://github.com/seamplex/suncae/discussions). 53 | 54 | 55 | ### What are the supported solvers? 56 | 57 | * [FeenoX](http://www.seamplex.com/feenox) 58 | * [CalculiX](https://www.dhondt.de/) 59 | 60 | The "single source of truth" is still the FeenoX input file. 61 | CalculiX is supportted through the [`fee2ccx` converter](https://github.com/seamplex/feenox/tree/main/utils/fee2ccx) from `.fee` to `.inp`. 62 | 63 | See the directory [`solvers`](https://github.com/seamplex/suncae/tree/main/solvers) for the current list. 64 | 65 | > [!NOTE] 66 | > If you want other solvers to be supported, say so in the [forum](https://github.com/seamplex/suncae/discussions). 67 | 68 | -------------------------------------------------------------------------------- /doc/INSTALL.md: -------------------------------------------------------------------------------- 1 | # Installing and setting up SunCAE 2 | 3 | > [!TIP] 4 | > If you just want to use SunCAE without installing it, you can do so with the [live demo](https://www.caeplex.com/suncae). 5 | 6 | > [!NOTE] 7 | > Mind the license of SunCAE itself and the license of all the related packages that SunCAE uses to make sure you are not infringing any license. 8 | 9 | This document explains how to set up [SunCAE](https://www.seamplex.com/suncae) so as to serve one or more clients. 10 | A basic installation can be done relatively simple, even without understanding the meaning of the commands. 11 | Keep in mind that a full-fledged installation being able to serve different users might need deep understanding of networking administration and operating systems details. 12 | 13 | ## Architectures 14 | 15 | The code is aimed at being run on Unix systems. Specifically, Debian GNU/Linux. 16 | There might be ways of making SunCAE run on other architectures. 17 | If you happen to know how, please help us by explaining how. 18 | 19 | ## Cloning the repository 20 | 21 | The first step would be to clone the SunCAE repository: 22 | 23 | ``` 24 | git clone https://github.com/seamplex/suncae 25 | cd suncae 26 | ``` 27 | 28 | 29 | ## Dependencies 30 | 31 | The repository only hosts particular code and files which are not already available somewhere else. 32 | The latter include 33 | 34 | * meshers and solvers executables (e.g. `gmsh`, `feenox`, `ccx`, etc.) 35 | * Javascript libraries (e.g. `x3dom.js`) 36 | * CSS and fonts (e.g. `bootstrap.css`) 37 | 38 | 39 | ### Common 40 | 41 | SunCAE needs some functionality which is provided by packages which are commonly available in the most common GNU/Linux distribution repositories. Ranging from the web server itself, script interpreters (e.g. PHP and Bash) and other standard Unix utilities, this line (or a similar one for a non-Debian distribution) should be enough: 42 | 43 | ``` 44 | sudo apt-get install git unzip patchelf wget php-cli php-yaml gnuplot 45 | ``` 46 | 47 | ### Particular 48 | 49 | The (free and open source) meshers, solvers and required libraries and fonts can be downloaded by executing the `deps.sh` script in SunCAE's root directory: 50 | 51 | ``` 52 | ./deps.sh 53 | ``` 54 | 55 | > [!IMPORTANT] 56 | > Run the script from SunCAE's root directory, i.e. 57 | > 58 | > ``` 59 | > ./deps.sh 60 | > ``` 61 | > 62 | > and **not** from the parent (or any other directory) like 63 | > 64 | > ``` 65 | > suncae/dep.sh 66 | > ``` 67 | 68 | > [!TIP] 69 | > The script will try to download and copy the dependencies inside SunCAE's directories (ignored by Git) only if they are not already copied. To force the download and copy (say if the version changed), you can either delete the dependencies or pass `--force` to `deps.sh` 70 | > 71 | > ``` 72 | > ./deps.sh --force 73 | > ``` 74 | 75 | 76 | ## The web server 77 | 78 | SunCAE can be hosted with any web server capable of executing PHP scripts. 79 | The main entry point is under directory `html`. 80 | 81 | All the user information is stored as files under the directory `data`. 82 | That is to say, there is not **database** (either SQL or Mongo-like). 83 | Just plain (Git-tracked) files. 84 | 85 | > [!TIP] 86 | > Backups are as simple as `cp`ing (or `rsync`ing, `tar`ring, etc.) the directory `data` somewhere else. 87 | 88 | 89 | 90 | ### PHP's internal web server 91 | 92 | The `php-cli` package includes a simple web server which is enough to host SunCAE for single-user mode (and it is even handy for debugging purposes). 93 | Just run `php` with the `-S` option. Choose an available port and pass the `html` directory in the `-t` option (or go into the `html` directory and run `php -S` from there without `-t`): 94 | 95 | ```terminal 96 | php -S localhost:8000 -t html 97 | ``` 98 | 99 | > [!IMPORTANT] 100 | > The first time that SunCAE needs to use the `data` directory, it will be created and owned by the user running the server, which in this case will be the user that ran `php`. 101 | > Mind ownerships and permissions if you then change from the internal web server to a professional one such as Apache. 102 | 103 | ### Apache 104 | 105 | Configure Apache to serve the `html` directory in SunCAE's repository. 106 | By default, Apache's root directory is `/var/www/html`. 107 | 108 | A quick hack is to make sure that SunCAE’s [`html`](html) directory is available to be served. For instance, in the default installation you could do 109 | 110 | ```terminal 111 | ln -s html /var/www/html/suncae 112 | ``` 113 | 114 | and then SunCAE would be available at . 115 | 116 | > [!WARNING] 117 | > Mind Apache's policies about symbolic links. They are not straightforward, so symlinking SunCAE's `html` directory into Apache's `html` directory might not work out of the box. 118 | 119 | 120 | * If you do not have experience with Apache, you might want to delete the default `/var/www` tree and clone SunCAE there. 121 | * If you have experience with Apache, there is little more to add. 122 | 123 | 124 | > [!IMPORTANT] 125 | > The first time that SunCAE needs to use the `data` directory, it will be created and owned by the user running the server, which in this case by default is `www-data`. 126 | > Mind ownerships and permissions when accessing `data`. 127 | 128 | ### Other servers 129 | 130 | We do not know. 131 | 132 | 133 | ## Stack configuration 134 | 135 | The file [`conf.php`](../conf.php) in SunCAE's root directory controls the choices of the implementations of the different components for the current instance of SunCAE being served: 136 | 137 | ```php 138 | $auth = "single-user"; 139 | $ux = "faster-than-quick"; 140 | $cadimporter = "upload"; 141 | $cadprocessor = "gmsh"; 142 | $runner = "local"; 143 | $max_nodes = 100e3; 144 | ``` 145 | 146 | This means that 147 | 148 | 1. the same server can change the implementations by changing the content of `conf.php` dynamically 149 | 2. different servers (or the same server with different entry points) can serve different implementations by serving different `html` directories whose parent's `conf.php` is different. 150 | 3. any other combination is also possible, e.g. an interactive HTML-based panel that modifies `conf.php` on demand or that clones a new instance of SunCAE in an arbitrary location (and configures Apache to serve it). 151 | 152 | Read the [Design Manual](design.md) for details about what each of the definitions mean. 153 | 154 | -------------------------------------------------------------------------------- /doc/README.md: -------------------------------------------------------------------------------- 1 | # SunCAE documentation 2 | 3 | * [Installation guide](INSTALL.md) 4 | * [Tutorials](tutorials.md) 5 | * [FAQs](FAQs.md) 6 | * [Explanation of the workflow](workflow.md) 7 | -------------------------------------------------------------------------------- /doc/design.md: -------------------------------------------------------------------------------- 1 | # SunCAE design description 2 | 3 | SunCAE is split into a front end and a back end. 4 | 5 | * The front end is HTML + Javascript running on a web browser on any operating system (even mobile devices). 6 | * The back end is PHP + Bash + Python + particular binaries running on one or more Unix servers. 7 | 8 | The spirit is that the definition of the CAE problem being solved is stored in a single source of truth as a text file, hopefully the actual solver's input file. The web-based interface should allow both 9 | 10 | 1. To update the solver's input file from the status of web-based widgets (e.g. picking faces in the 3D model to hold boundary conditions, entering material properties in text boxes, choosing sdef/ldef from a combo box, etc.), and 11 | 2. To allow the user to edit the input file and then to update the status of web-based widgets from the contents of the input file. 12 | 13 | For instance, consider the following [FeenoX](https://www.seamplex.com/feenox/) input file: 14 | 15 | ``` 16 | PROBLEM mechanical READ_MESH meshes/9061bd607902d31a8aac5f97a1066504-2.msh 17 | 18 | E(x,y,z) = 200e3 19 | nu = 0.3 20 | 21 | BC face1 fixed 22 | BC face3 Fx=10e3 23 | ``` 24 | 25 | If the user changes the value of the Young's modulus to `210e3`, the front end issues an AJAX call and the back end updates the file. 26 | Conversely, if the user edits the input file (through a web-based editor the UX has to provide) and changes the value in the file to something else, then the back-end sends instructions to the front end to update the web-based interface. 27 | Moreover, each time the file changes (either because of the user changing a value in the interface or editing the file), a Git commit is issued. Therefore, every single change in the single source of truth is tracked (what? who? when?). 28 | 29 | # The SunCAE interface 30 | 31 | The SunCAE interface consists of four steps divided into two stages: 32 | 33 | 1. New case 34 | 1. CAD import, physics, problem, mesher and solver selection 35 | 2. Case view 36 | 1. Mesh 37 | 2. Problem 38 | 3. Results 39 | 40 | The source code of the index page at [html/index.php](../html/index.php) looks like this 41 | 42 | ```php 43 | include("../conf.php"); 44 | include("../auths/{$auth}/auth.php"); 45 | include("common.php"); 46 | include("case.php"); 47 | include("../uxs/{$ux}/index.php"); 48 | ``` 49 | 50 | * The [`conf.php`](../conf.php) file is included first. 51 | * The authorization scheme `$auth` defined in `conf.php` is included. 52 | This step should ask for authentication/authorization, set/read cookies, etc. 53 | PHP's [session_start()](https://www.php.net/manual/en/function.session-start.php) can be used. 54 | This file should define a non-empty global PHP string `$username`. 55 | The default [`single-user`](../auths/single-user/auth.php) auth scheme just does 56 | 57 | ```php 58 | $username = "root"; 59 | ``` 60 | 61 | * The file `common.php` defines common functions and methods needed by the back end. 62 | It also defines a PHP variable `$id` coming from either a `GET` or `POST` argument with name `id`: 63 | 64 | ```php 65 | $id = (isset($_POST["id"])) ? $_POST["id"] : ((isset($_GET["id"])) ? $_GET["id"] : ""); 66 | ``` 67 | 68 | This should be the `id` of an existing case. 69 | 70 | * The file `case.php` reads the metadata for the case `id`. But, if the variable `$id` is empty, it will re-direct the user to the ["New case"](#new-case) page at `new/`: 71 | 72 | ```php 73 | if ($id == "") { 74 | header("Location: new/"); 75 | exit(); 76 | } 77 | ``` 78 | 79 | * If `$id` is not empty, the workflow continues to include the `$ux` scheme defined in `conf.php` which should load case `$id` and show the ["Case view"](#case-view), loading either the mesh, problem or results view depending on the state of the case. 80 | 81 | 82 | ## New case 83 | 84 | The [`html/new/index.php`](../html/new/index.php) source is 85 | 86 | ```php 87 | include("../../conf.php"); 88 | include("../../auths/{$auth}/auth.php"); 89 | include("../common.php"); 90 | include("../../uxs/{$ux}/new.php"); 91 | ``` 92 | 93 | The first three lines have been already discussed. 94 | The default `$ux` is `faster-than-quick`. As its name suggest, it is a quick hack that works. 95 | 96 | To be completed. 97 | 98 | ## Case view 99 | 100 | To be completed. 101 | -------------------------------------------------------------------------------- /doc/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 16 | 37 | 42 | 43 | 45 | 50 | 57 | 61 | 65 | 70 | 75 | 80 | 81 | 82 | 88 | Sun 99 | 100 | 101 | -------------------------------------------------------------------------------- /doc/virtual.md: -------------------------------------------------------------------------------- 1 | # Setting up virtual machines to host SunCAE 2 | 3 | ## Vagrant 4 | 5 | ```terminal 6 | vagrant init debian/bookworm64 7 | vagrant up 8 | vagrant ssh 9 | ``` 10 | 11 | ## Docker 12 | 13 | TBD 14 | -------------------------------------------------------------------------------- /doc/workflow.md: -------------------------------------------------------------------------------- 1 | # New case 2 | 3 | #. if someone goes to the root `index.php` (at `html/index.php`) without and `id` or directly to `new/` then the "new case" page at `new/index.php` is shown 4 | #. that one includes `uxs/$ux/new.php` 5 | 6 | ## Faster-than-quick UX 7 | 8 | #. `uxs/faster-than-quick/new.php` shows the four choices 9 | 10 | 2. Physics 11 | 3. Problem 12 | 4. Solver 13 | 5. Mesher 14 | 15 | But the first one, which is the CAD, comes from `uxs/faster-than-quick/importers/$cadimporter.php` 16 | 17 | ## Upload-importer 18 | 19 | #. `uxs/faster-than-quick/importers/upload.php` shows a file upload HTML component with an onchange call to `upload_cad_file()` that after uploading the CAD, calls `process_cad()`. 20 | #. `process_cad()` in `uxs/faster-than-quick/new.php` calls `html/new/process.php` which includes `cadprocessors/$cadprocessor/process.php` 21 | 22 | ## Gmsh-processor 23 | 24 | #. `cadprocessors/gmsh/process.php` uses `cadimport.py` to process the uploaded CAD with Gmsh (through OCC) to create a `.xao` 25 | #. It calls `initial_mesh.sh` in background to create the first mesh. 26 | #. This `initial_mesh.sh` just calls `cadmesh.py` if `default.geo` does not exit. 27 | #. `cadmesh.py` performs five attempts to create an initial mesh by calling `trymesh.py` with the number of attempt $i$ as the argument 28 | #. `trymesh.py` merges `defaulti.geo` and then tries to come up with a max $\ell_c$ 29 | #. 30 | 31 | -------------------------------------------------------------------------------- /html/.htaccess: -------------------------------------------------------------------------------- 1 | # AuthType Basic 2 | # AuthName "Restricted Content" 3 | # AuthUserFile /home/gtheler/codigos/suncae/auths/htpasswd/.htpasswd 4 | # Require valid-user 5 | -------------------------------------------------------------------------------- /html/ajax2mesh.php: -------------------------------------------------------------------------------- 1 | 107 | -------------------------------------------------------------------------------- /html/change_step.php: -------------------------------------------------------------------------------- 1 | SunCAE found a fatal error:"; 11 | echo $error; 12 | echo "

"; 13 | exit(); 14 | } 15 | 16 | 17 | function return_back_html($response) { 18 | header("Content-Type: text/html"); 19 | echo $response; 20 | exit(); 21 | } 22 | 23 | function return_error_html($error) { 24 | header("Content-Type: text/html"); 25 | echo $response; 26 | exit(); 27 | } 28 | 29 | function return_back_json($response) { 30 | header("Content-Type: application/json"); 31 | echo json_encode($response); 32 | exit(); 33 | } 34 | 35 | function return_error_json($error) { 36 | $response["error"] = $error; 37 | suncae_log($error); 38 | return_back_json($response); 39 | exit(); 40 | } 41 | 42 | // based on original work from the PHP Laravel framework 43 | if (!function_exists('str_contains')) { 44 | function str_contains($haystack, $needle) { 45 | return $needle !== '' && mb_strpos($haystack, $needle) !== false; 46 | } 47 | } 48 | 49 | function suncae_log($message) { 50 | global $permissions; 51 | global $username; 52 | $log_dir = __DIR__ . "/../data/logs/"; 53 | if (file_exists($log_dir) == false) { 54 | if (mkdir($log_dir, $permissions, true) == false) { 55 | echo "error: cannot create log directory"; 56 | exit(); 57 | } 58 | } 59 | $log = fopen($log_dir . date("Y-m-d").".log", "a"); 60 | if ($log === false) { 61 | echo "Cannot open log file, please check permissions."; 62 | exit(1); 63 | } 64 | fprintf($log, "%s %s\t%s: %s\n", date("c"), $_SERVER['REMOTE_ADDR'], $username, $message); 65 | fclose($log); 66 | } 67 | -------------------------------------------------------------------------------- /html/css/faster-than-quick: -------------------------------------------------------------------------------- 1 | ../../uxs/faster-than-quick/css/ -------------------------------------------------------------------------------- /html/expert.php: -------------------------------------------------------------------------------- 1 | &1", $output, $result); 60 | if ($result != 0) { 61 | for ($i = 0; $i < count($output); $i++) { 62 | if (strncmp("Error", $output[$i], 5) == 0) { 63 | $output_exploded = explode(":", $output[$i]); 64 | for ($j = 1; $j < count($output_exploded); $j++) { 65 | $response["error"] .= $output_exploded[$j] ; 66 | } 67 | $response["error"] .= "
"; 68 | } 69 | } 70 | } 71 | 72 | } else { 73 | return_error_json("cannot open mesh.geo"); 74 | } 75 | $mesh_hash = mesh_hash(); 76 | 77 | exec("git commit -a -m 'mesh {$field} = {$value}'", $output, $result); 78 | if ($result != 0) { 79 | return_error_json("cannot git commit {$id}: {$output[0]}"); 80 | } 81 | suncae_log("mesh {$id} ajax2yaml {$field} = {$value}"); 82 | 83 | if ($response["error"] != "") { 84 | suncae_log("mesh {$id} error: {$response["error"]}"); 85 | } 86 | 87 | return_back_json($response); 88 | -------------------------------------------------------------------------------- /meshers/gmsh/cadmesh.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | import os 3 | import sys 4 | import json 5 | 6 | 7 | def mesh(attempt): 8 | os.system("timeout 30 ../../../../meshers/gmsh/trymesh.py %d > attempt%d.log 2>&1" % (attempt, attempt)) 9 | if os.path.exists("attempt%d.json" % attempt): 10 | fp = open("attempt%d.json" % attempt) 11 | result = json.load(fp) 12 | fp.close() 13 | return result["result"] == "success" 14 | else: 15 | return False 16 | 17 | def main(): 18 | 19 | # write a basic default.geo and close it so it's available in case it's needed 20 | geo = open("default.geo", "w") 21 | geo.write("Merge \"../../cads/%s/cad.xao\";\n" % os.path.basename(os.path.normpath(os.getcwd()))) 22 | geo.close() 23 | 24 | # try to obtain a valid mesh 25 | i = 0; 26 | i_max = 5; 27 | while mesh(i) == False: 28 | print("%d-th attempt failed" % (i)) 29 | i += 1 30 | if i == i_max+1: 31 | print("max attempts reached") 32 | sys.exit(1) 33 | 34 | print("final success with attempt = %d" % i) 35 | 36 | # append what worked 37 | geo = open("default.geo", "a") 38 | if True: 39 | print(i) 40 | fp = open("attempt%d.json" % i) 41 | attempt = json.load(fp) 42 | fp.close() 43 | 44 | print(attempt) 45 | if attempt["lc"] != 0: 46 | lc = float(attempt["lc"]) 47 | geo.write("Mesh.MeshSizeMax = %g;\n" % (lc)); 48 | geo.write("Mesh.MeshSizeMin = %g;\n" % (1e-2*lc)); 49 | 50 | default = open("../../../../meshers/gmsh/default%d.geo" % i) 51 | geo.write(default.read()) 52 | default.close() 53 | geo.close() 54 | 55 | if os.path.exists("meshes") == False: 56 | os.system("../../../../meshers/gmsh/mesh.sh cad"); 57 | sys.exit(0) 58 | 59 | if __name__ == "__main__": 60 | main() 61 | -------------------------------------------------------------------------------- /meshers/gmsh/default0.geo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seamplex/suncae/0bdb8483ee659a6bbd3b958d2a9b8da87b94125e/meshers/gmsh/default0.geo -------------------------------------------------------------------------------- /meshers/gmsh/default1.geo: -------------------------------------------------------------------------------- 1 | Mesh.MeshSizeFromCurvature = 5; 2 | -------------------------------------------------------------------------------- /meshers/gmsh/default2.geo: -------------------------------------------------------------------------------- 1 | Mesh.MeshSizeFromCurvature = 10; 2 | Mesh.Algorithm = 1; 3 | -------------------------------------------------------------------------------- /meshers/gmsh/default3.geo: -------------------------------------------------------------------------------- 1 | Mesh.MeshSizeFromCurvature = 12; 2 | Mesh.AlgorithmSwitchOnFailure = 1; 3 | Mesh.Algorithm = 2; 4 | -------------------------------------------------------------------------------- /meshers/gmsh/default4.geo: -------------------------------------------------------------------------------- 1 | Mesh.MeshSizeFromCurvature = 16; 2 | Mesh.MeshSizeExtendFromBoundary = 1; 3 | Mesh.AlgorithmSwitchOnFailure = 1; 4 | Mesh.MinimumLineNodes = 8; 5 | Mesh.Algorithm = 2; 6 | -------------------------------------------------------------------------------- /meshers/gmsh/default5.geo: -------------------------------------------------------------------------------- 1 | Mesh.MeshSizeFromCurvature = 20; 2 | Mesh.MeshSizeExtendFromBoundary = 1; 3 | Mesh.MinimumLineNodes = 8; 4 | Mesh.Algorithm = 2; 5 | Mesh.MeshSizeFactor = 0.5; 6 | -------------------------------------------------------------------------------- /meshers/gmsh/deps.sh: -------------------------------------------------------------------------------- 1 | #!/bin/false 2 | 3 | gmsh_version=4.14.0 4 | 5 | # gmsh 6 | echo -n "meshers/gmsh... " 7 | # gmsh_tarball=gmsh-nox-git-Linux64-sdk 8 | gmsh_tarball=gmsh-${gmsh_version}-Linux64-sdk 9 | if [ $force = 1 ] || [ ! -x bin/gmsh ] || [ ! -f deps/${gmsh_tarball}.tgz ]; then 10 | cd deps 11 | if [ ! -e ${gmsh_tarball}.tgz ]; then 12 | wget -c http://gmsh.info/bin/Linux/${gmsh_tarball}.tgz 13 | fi 14 | tar xzf ${gmsh_tarball}.tgz 15 | cp ${gmsh_tarball}/bin/gmsh ../bin 16 | cp ${gmsh_tarball}/lib/gmsh.py ../bin 17 | cp -d ${gmsh_tarball}/lib/libgmsh.so* ../bin 18 | cd ../bin 19 | # this is needed to add pwd to the binary's rpath 20 | patchelf --set-rpath ${PWD} gmsh 21 | echo "done" 22 | cd .. 23 | else 24 | echo "already installed" 25 | fi 26 | -------------------------------------------------------------------------------- /meshers/gmsh/mesh.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -x 2 | 3 | usage="case" 4 | if [ ! -z "${1}" ]; then 5 | usage="cad" 6 | fi 7 | 8 | if [ "x${usage}" == "xcase" ]; then 9 | dir="run" 10 | mesh="mesh" 11 | if [ ! -d ${dir}/meshes ]; then 12 | echo "error: ${dir}/meshes dir does not exist" 13 | exit 1 14 | fi 15 | else 16 | dir="." 17 | mesh="default" 18 | if [ ! -d ${dir}/meshes ]; then 19 | mkdir -p ${dir}/meshes 20 | fi 21 | fi 22 | 23 | if [ ! -e ./${mesh}.geo ]; then 24 | echo "error: run from case directory" 25 | exit 1 26 | fi 27 | 28 | mesh_hash=($(md5sum ${mesh}.geo)) 29 | 30 | cat << EOF > ${dir}/meshes/${mesh_hash}.json 31 | { 32 | "status": "running", 33 | "pid": $$ 34 | } 35 | EOF 36 | 37 | # TODO: time & memory (maybe we can read it from the log) 38 | ../../../../bin/gmsh -check ${mesh}.geo 1> ${dir}/meshes/${mesh_hash}.1 2> ${dir}/meshes/${mesh_hash}.2 39 | if [ $? -eq 0 ]; then 40 | ../../../../bin/gmsh -3 ${mesh}.geo -o ${dir}/meshes/${mesh_hash}.msh 1> ${dir}/meshes/${mesh_hash}.1 2> ${dir}/meshes/${mesh_hash}.2 41 | 42 | # the meshing could have worked or not, that's in $? 43 | gmsh_error=$? 44 | if [ "x${gmsh_error}" != "x0" ]; then 45 | echo ${dir}/meshes/${mesh_hash}.2 > tmp 46 | cat ${dir}/meshes/${mesh_hash}.2 | grep -v "No elements" | \ 47 | grep -v "\-\-\-\-\-\-\-\-\-\-\-" | \ 48 | grep -v "Mesh generation error summary" | \ 49 | grep -v " warning" | \ 50 | grep -v " errors" | \ 51 | grep -v "Check the full log for details" > tmp 52 | 53 | sed -n 's/.*intersection (\([^)]*\)).*/\1/p' tmp | tr ',' ' ' | head -n1 > ${dir}/meshes/${mesh_hash}.intersections 54 | mv tmp ${dir}/meshes/${mesh_hash}.2 55 | fi 56 | 57 | # we can have a partial mesh, though 58 | # TODO: rewrite mesh_data in C++ 59 | if [ -e ${dir}/meshes/${mesh_hash}.msh ]; then 60 | ../../../../meshers/gmsh/mesh_data.py ${mesh_hash} ${dir}/meshes > ${dir}/meshes/${mesh_hash}-data.log 61 | fi 62 | 63 | # the metadata depends on whether the mesh worked or not 64 | ../../../../meshers/gmsh/mesh_meta.py ${dir}/meshes/${mesh_hash} ${gmsh_error} > ${dir}/meshes/${mesh_hash}.json 65 | if [ -e ${dir}/meshes/${mesh_hash}.gp ]; then 66 | # TODO: bin 67 | gnuplot ${dir}/meshes/${mesh_hash}.gp 68 | fi 69 | # TODO: should we remove this guy? 70 | # rm -f ${dir}/meshes/${mesh_hash}-status.json 71 | 72 | else 73 | cat << EOF > ${dir}/meshes/${mesh_hash}.json 74 | { 75 | "status": "syntax_error" 76 | } 77 | EOF 78 | fi 79 | 80 | # sync run/meshes/${mesh_hash}.json 81 | rm -f ${dir}/${mesh_hash}.pid 82 | -------------------------------------------------------------------------------- /meshers/gmsh/mesh_data.php: -------------------------------------------------------------------------------- 1 | &1", $output, $result); 17 | if ($result != 0) { 18 | $response["status"] = "error"; 19 | for ($i = 0; $i < count($output); $i++) { 20 | if (strncmp("Error", $output[$i], 5) == 0) { 21 | $response["error"] .= $output[$i] . "
"; 22 | } 23 | } 24 | } 25 | 26 | return_back_json($response); 27 | -------------------------------------------------------------------------------- /meshers/gmsh/mesh_inp_show.php: -------------------------------------------------------------------------------- 1 | run/meshes/${mesh_hash}-status.json 47 | { 48 | "status": "running", 49 | "pid": ${gmsh_pid}, 50 | "edges": ${edges}, 51 | "faces": ${faces}, 52 | "volumes": ${volumes}, 53 | "data": ${data}, 54 | "done_edges": ${done_edges}, 55 | "done_faces": ${done_faces}, 56 | "done_volumes": ${done_volumes}, 57 | "done_data": ${done_data}, 58 | "log": "$(tail -n5 run/meshes/${mesh_hash}.1 | cut -d: -f 2- | awk '{printf "%s\\n", $0}')" 59 | } 60 | EOF 61 | # sync run/meshes/${mesh_hash}.json 62 | 63 | else 64 | exit 0 65 | fi 66 | -------------------------------------------------------------------------------- /meshers/gmsh/meshing_relaunch.php: -------------------------------------------------------------------------------- 1 | 62 | -------------------------------------------------------------------------------- /meshers/gmsh/process_step.php: -------------------------------------------------------------------------------- 1 | 1) { 32 | $response["status"] = "error"; 33 | $response["error"] = "CAD file has {$original["solids"]} solids and this PoC works with single-solid CADs only."; 34 | } 35 | } else { 36 | $response["status"] = "error"; 37 | $response["show_preview"] = false; 38 | $response["error"] = "Cannot decode original json."; 39 | } 40 | 41 | } else { 42 | $response["status"] = "error"; 43 | $response["show_preview"] = false; 44 | $response["error"] = "Cannot create original json."; 45 | } 46 | 47 | suncae_log("CAD {$response["cad_hash"]} upload {$response["status"]} {$response["error"]}"); 48 | 49 | ?> 50 | -------------------------------------------------------------------------------- /meshers/gmsh/quality.gp: -------------------------------------------------------------------------------- 1 | set style fill transparent solid 0.50 noborder 2 | set style function filledcurves y1=0 3 | plot "data" u (($1+0.5)/10):3 with boxes, "data" u (($1+0.5)/10):4 with boxes, "data" u (($1+0.5)/10):2 with boxes 4 | -------------------------------------------------------------------------------- /meshers/gmsh/quality.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | import sys 3 | sys.path.append("../../../../bin") 4 | import gmsh 5 | import math 6 | 7 | gmsh.initialize(sys.argv) 8 | gmsh.option.setNumber("General.Terminal", 0) 9 | 10 | gmsh.open("mesh.msh") 11 | 12 | ## get element qualities: 13 | #_, eleTags , _ = gmsh.model.mesh.getElements(dim=3) 14 | #q = gmsh.model.mesh.getElementQualities(eleTags[0], "minSICN") 15 | #print(zip(eleTags[0], q)) 16 | 17 | gmsh.plugin.setNumber("AnalyseMeshQuality", "JacobianDeterminant", 1.) 18 | gmsh.plugin.setNumber("AnalyseMeshQuality", "IGEMeasure", 1.) 19 | gmsh.plugin.setNumber("AnalyseMeshQuality", "ICNMeasure", 1.) 20 | 21 | gmsh.plugin.setNumber("AnalyseMeshQuality", "CreateView", 1.) 22 | gmsh.plugin.run("AnalyseMeshQuality") 23 | 24 | dataType, tags, Jac, time, numComp = gmsh.view.getModelData(0, 0) 25 | dataType, tags, IGE, time, numComp = gmsh.view.getModelData(1, 0) 26 | dataType, tags, ICN, time, numComp = gmsh.view.getModelData(2, 0) 27 | 28 | N = 20 29 | hist_Jac = [0]*(N+1) 30 | hist_IGE = [0]*(N+1) 31 | hist_ICN = [0]*(N+1) 32 | 33 | 34 | for i in range(len(tags)): 35 | n_Jac = int(math.floor(Jac[i][0]*N)) 36 | n_IGE = int(math.floor(IGE[i][0]*N)) 37 | n_ICN = int(math.floor(ICN[i][0]*N)) 38 | #print(n_Jac, n_IGE, n_ICN) 39 | hist_Jac[n_Jac] += 1 40 | hist_IGE[n_IGE] += 1 41 | hist_ICN[n_ICN] += 1 42 | 43 | # for qualities = 1 they go to N and we move it to N-1 44 | hist_Jac[N-1] += hist_Jac[N] 45 | hist_IGE[N-1] += hist_IGE[N] 46 | hist_ICN[N-1] += hist_ICN[N] 47 | 48 | 49 | for j in range(N): 50 | print("{0}\t{1}\t{2}\t{3}".format(j,hist_Jac[j],hist_IGE[j],hist_ICN[j])) 51 | 52 | gmsh.finalize() 53 | -------------------------------------------------------------------------------- /meshers/gmsh/trymesh.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | import sys 3 | sys.path.append("../../../../bin") 4 | import gmsh 5 | import math 6 | import os 7 | import json 8 | import signal 9 | 10 | def mesh(attempt): 11 | result = {} 12 | gmsh.initialize() 13 | gmsh.option.setNumber("General.Terminal", 1) 14 | # gmsh.option.setNumber("General.Verbosity", 1) # (0: silent except for fatal errors, 1: +errors, 2: +warnings, 3: +direct, 4: +information, 5: +status, 99: +debug) 15 | 16 | # now we do not care about optimization, then in the actual mesh step we will optimize 17 | gmsh.option.setNumber("Mesh.Optimize", 0) 18 | gmsh.merge("cad.xao") 19 | if attempt != 0: 20 | gmsh.merge("../../../../meshers/gmsh/default%d.geo" % attempt) 21 | 22 | cad_json_file = open("cad.json") 23 | cad = json.load(cad_json_file) 24 | cad_json_file.close() 25 | length_order = math.pow(10, math.floor(math.log10(cad["max_length"]))) 26 | length_precision = 1e-2 * length_order 27 | length_char = 4*cad["volume"]/cad["area"] 28 | lc1 = length_char * (1+0.125*(3-attempt)) 29 | lc2 = cad["max_length"] / (4 * (1 + attempt)) 30 | lc = math.ceil(min([lc1, lc2]) / length_precision) * length_precision 31 | print("length_order", length_order) 32 | print("length_precision", length_precision) 33 | print("length_char", length_char) 34 | print("lc1", lc1) 35 | 36 | gmsh.option.setNumber("Mesh.MeshSizeMax", lc) 37 | gmsh.option.setNumber("Mesh.MeshSizeMin", 1e-2*lc) 38 | 39 | try: 40 | gmsh.model.mesh.generate(3) 41 | 42 | except: 43 | result["result"] = "failed" 44 | nodes, _, _ = gmsh.model.mesh.getNodes() 45 | result["lc"] = lc 46 | result["nodes"] = len(nodes) 47 | result["error"] = gmsh.logger.getLastError() 48 | result["error_entity"] = list(gmsh.model.mesh.getLastEntityError()) 49 | # numpy uses uint64 which json does not like 50 | result["error_node"] = list() 51 | for n in gmsh.model.mesh.getLastNodeError(): 52 | result["error_node"].append(int(n)) 53 | return result 54 | 55 | result["result"] = "success" 56 | nodes, _, _ = gmsh.model.mesh.getNodes() 57 | result["lc"] = lc 58 | result["nodes"] = len(nodes) 59 | gmsh.finalize() 60 | return result 61 | 62 | #def handler(signum, frame): 63 | #signame = signal.Signals(signum).name 64 | #print(f'Signal handler called with signal {signame} ({signum})') 65 | #sys.exit(1) 66 | 67 | # gmsh installs some signal handlers of its own 68 | # I cannot seem to catch signals 69 | #signal.signal(signal.SIGTERM, handler) 70 | #signal.signal(signal.SIGINT, handler) 71 | #signal.signal(signal.SIGKILL, handler) 72 | #signal.signal(signal.SIGHUP, handler) 73 | 74 | 75 | def main(): 76 | if len(sys.argv) == 2: 77 | json_file = "attempt%d.json" % (int(sys.argv[1])) 78 | if os.path.exists(json_file): 79 | os.remove(json_file) 80 | result = mesh(int(sys.argv[1])) 81 | with open(json_file, "w") as fp: 82 | json.dump(result, fp, indent=2) 83 | 84 | if __name__ == "__main__": 85 | main() 86 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /renderers/x3dom/.gitignore: -------------------------------------------------------------------------------- 1 | x3dom.css 2 | x3dom.js 3 | -------------------------------------------------------------------------------- /renderers/x3dom/LICENSE: -------------------------------------------------------------------------------- 1 | MIT/GPLv3+ -------------------------------------------------------------------------------- /renderers/x3dom/deps.sh: -------------------------------------------------------------------------------- 1 | #!/bin/false 2 | 3 | # x3dom_version=1.8.3 4 | x3dom_version=1.8.4-dev 5 | 6 | echo -n "renderers/x3dom: x3dom.js & x3dom.css... " 7 | if [ $force = 1 ] || [ ! -e renderers/x3dom/x3dom.js ]; then 8 | cd deps 9 | x3dom_tarball=x3dom-${x3dom_version} 10 | 11 | # if [ ! -e ${x3dom_tarball}.zip ]; then 12 | # wget -c https://www.x3dom.org/download/${x3dom_version}/${x3dom_tarball}.zip 13 | # wget -c https://www.x3dom.org/download/dev/${x3dom_tarball}.zip 14 | # fi 15 | # if [ ! -d x3dom ]; then 16 | # mkdir -p x3dom 17 | # unzip ${x3dom_tarball}.zip -d x3dom 18 | # fi 19 | # cp x3dom/x3dom.js ../renderers/x3dom 20 | # cp x3dom/x3dom.css ../renderers/x3dom 21 | 22 | wget -c https://andreasplesch.github.io/x3dom/dist/x3dom.js 23 | cp x3dom.js ../renderers/x3dom 24 | wget -c https://andreasplesch.github.io/x3dom/dist/x3dom.css 25 | cp x3dom.css ../renderers/x3dom 26 | 27 | cd ../uxs/faster-than-quick/js 28 | if [ ! -e x3dom.js ]; then 29 | ln -s ../../../renderers/x3dom/x3dom.js 30 | fi 31 | cd ../css 32 | if [ ! -e x3dom.css ]; then 33 | ln -s ../../../renderers/x3dom/x3dom.css 34 | fi 35 | echo "done" 36 | cd ../../.. 37 | else 38 | echo "already installed" 39 | fi 40 | -------------------------------------------------------------------------------- /solvers/README.md: -------------------------------------------------------------------------------- 1 | # Solvers 2 | 3 | * [FeenoX](https://www.seamplex.com/feenox) (GPLv3+) 4 | * [CalculiX](http://calculix.de/) (GPLv3+)---through the [`fee2ccx`](https://github.com/seamplex/feenox/tree/main/utils/fee2ccx) converter 5 | -------------------------------------------------------------------------------- /solvers/ccx/LICENSE: -------------------------------------------------------------------------------- 1 | GPLv2+ -------------------------------------------------------------------------------- /solvers/ccx/ajax2problem.php: -------------------------------------------------------------------------------- 1 | ../feenox/ajax2problem.php -------------------------------------------------------------------------------- /solvers/ccx/change_step_solve.php: -------------------------------------------------------------------------------- 1 | run/{$problem_hash}-check.2", $output, $result); 9 | if ($result == 0) { 10 | exec("../../../../solvers/ccx/solve.sh {$problem} > run/{$problem_hash}-solve.log 2>&1 & echo $! > run/solving.pid"); 11 | $results_meta["status"] = "running"; 12 | suncae_log("{$id} problem running"); 13 | } else { 14 | $results_meta["status"] = "syntax_error"; 15 | suncae_log("{$id} problem syntax error"); 16 | } 17 | 18 | ?> 19 | -------------------------------------------------------------------------------- /solvers/ccx/common.php: -------------------------------------------------------------------------------- 1 | 56 | -------------------------------------------------------------------------------- /solvers/ccx/deps.sh: -------------------------------------------------------------------------------- 1 | #!/bin/false 2 | 3 | ccx_version=2.22 4 | 5 | # ccx 6 | echo -n "solvers/ccx... " 7 | # the one from http://www.dhondt.de/ccx_2.22.tar.bz2 needs libgfortran4 8 | # so I packed this one as a static binary 9 | ccx_tarball=ccx-${ccx_version}-linux-static 10 | if [ $force = 1 ] || [ ! -x bin/ccx ] || [ ! -f deps/${ccx_tarball}.tar.gz ]; then 11 | cd deps 12 | if [ ! -e ${ccx_tarball}.tar.gz ]; then 13 | wget -c https://www.seamplex.com/suncae/deps/${ccx_tarball}.tar.gz 14 | fi 15 | tar xzf ${ccx_tarball}.tar.gz 16 | cp ${ccx_tarball}/ccx ../bin 17 | echo "done" 18 | cd .. 19 | else 20 | echo "already installed" 21 | fi 22 | -------------------------------------------------------------------------------- /solvers/ccx/frd2vtk.fee: -------------------------------------------------------------------------------- 1 | READ_MESH $1.frd DIM 3 { 2 | READ_FIELD D1 AS displacements1 3 | READ_FIELD D2 AS displacements2 4 | READ_FIELD D3 AS displacements3 5 | # READ_FUNCTION EXX 6 | # READ_FUNCTION EYY 7 | # READ_FUNCTION EZZ 8 | # READ_FUNCTION EXY 9 | # READ_FUNCTION EYZ 10 | # READ_FUNCTION EZX 11 | READ_FUNCTION SXX 12 | READ_FUNCTION SYY 13 | READ_FUNCTION SZZ 14 | READ_FUNCTION SXY 15 | READ_FUNCTION SYZ 16 | READ_FUNCTION SZX 17 | } 18 | 19 | sigma(x,y,z) = sqrt(0.5*((SXX(x,y,z)-SYY(x,y,z))^2 + \ 20 | (SYY(x,y,z)-SZZ(x,y,z))^2 + \ 21 | (SZZ(x,y,z)-SXX(x,y,z))^2 + \ 22 | 6*(SXY(x,y,z)^2 + SYZ(x,y,z)^2 + SZX(x,y,z)^2))) 23 | 24 | WRITE_MESH $1.vtk { 25 | displacements1 displacements2 displacements3 26 | sigma 27 | # EXX EYY EZZ EXY EYZ EZX 28 | # SXX SYY SZZ SXY SYZ SZX 29 | } 30 | -------------------------------------------------------------------------------- /solvers/ccx/input_initial_mechanical.php: -------------------------------------------------------------------------------- 1 | ../feenox/input_initial_mechanical.php -------------------------------------------------------------------------------- /solvers/ccx/problem_fee.php: -------------------------------------------------------------------------------- 1 | ../feenox/problem_fee.php -------------------------------------------------------------------------------- /solvers/ccx/problem_fee_save.php: -------------------------------------------------------------------------------- 1 | ../feenox/problem_fee_save.php -------------------------------------------------------------------------------- /solvers/ccx/problems.php: -------------------------------------------------------------------------------- 1 | run/${problem_hash}.json 25 | { 26 | "status": "running", 27 | "pid": $$ 28 | } 29 | EOF 30 | 31 | cad=$(grep ^cad case.yaml | cut -f2 -d: | tr -d " ") 32 | max_length=$(jq .max_length ../../cads/${cad}/cad.json) 33 | 34 | cp case.fee run/${problem_hash}.fee || exit 2 35 | cd run || exit 3 36 | 37 | # check the syntax 38 | ../../../../../bin/feenox -c ${problem_hash}.fee 1> ${problem_hash}.1 2> ${problem_hash}.2 39 | if [ $? -eq 0 ]; then 40 | # all good! 41 | # see if we have the second-order mesh 42 | if [ ! -e meshes/${mesh_hash}-2.msh ]; then 43 | ../../../../../bin/gmsh -3 meshes/${mesh_hash}.msh -order 2 -o meshes/${mesh_hash}-2.msh > meshes/${mesh_hash}-2.1 44 | fi 45 | 46 | # convert from .fee to .inp 47 | ../../../../../bin/fee2ccx ${problem_hash}.fee > ${problem_hash}.inp 48 | 49 | # run 50 | ../../../../../bin/ccx -i ${problem_hash} 1> ${problem_hash}.1 2> ${problem_hash}.2 51 | ccx_error=$? 52 | 53 | if [ $ccx_error -eq 0 ]; then 54 | if [ "x${problem_type}" = "xmechanical" ]; then 55 | ../../../../../bin/feenox ../../../../../solvers/ccx/frd2vtk.fee ${problem_hash} 56 | ../../../../../bin/feenox ../../../../../solvers/feenox/second2first.fee ${problem_hash} ${mesh_hash} 57 | ../../../../../bin/feenox ../../../../../solvers/feenox/displacements.fee ${problem_hash} ${max_length} | tr -s ' \t\n' ' ' > ${problem_hash}-displacements.dat 58 | ../../../../../bin/feenox ../../../../../solvers/feenox/field1.fee ${problem_hash} sigma | tr -s ' \t\n' ' ' > ${problem_hash}-sigma.dat 59 | fi 60 | status="success" 61 | else 62 | status="error" 63 | fi 64 | else 65 | status="syntax_error" 66 | fi 67 | 68 | cat << EOF > ${problem_hash}.json 69 | { 70 | "status": "${status}" 71 | } 72 | EOF 73 | 74 | # sync run/meshes/${mesh_hash}.json 75 | rm -f ${dir}/${problem_hash}.pid 76 | -------------------------------------------------------------------------------- /solvers/ccx/solve_status.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -z "${1}" ]; then 4 | problem_hash=($(md5sum case.fee)) 5 | else 6 | problem_hash=${1} 7 | fi 8 | 9 | status=$(jq -r .status run/${problem_hash}.json) || exit 1 10 | if [ "x${status}" == "xrunning" ]; then 11 | feenox_pid=$(jq -r .pid run/${problem_hash}.json) 12 | echo $feenox_pid 13 | if [ -z "$(ps --no-headers --pid ${feenox_pid})" ]; then 14 | echo "solver pid ${feenox_pid} is not running" 15 | echo "TODO: check if it worked or not" 16 | exit 1 17 | fi 18 | 19 | mesh=0 20 | meshfile=$(grep MESH case.fee | awk '{print $4}' | head -n1) 21 | meshname=$(basename ${meshfile} .msh) 22 | if [ -e run/meshes/${meshname}.1 ]; then 23 | mesh=$(grep % run/meshes/${meshname}.1 | tr -d [] | awk '{print $3}' | tr -d % | tail -n1) 24 | fi 25 | 26 | logfile=run/${problem_hash}.1 27 | build=$(grep \\. ${logfile} | tr -d '\n' | wc -c) 28 | solve=$(grep \\- ${logfile} | tr -d '\n' | wc -c) 29 | post=$(grep = ${logfile} | tr -d '\n' | wc -c) 30 | data=50 31 | 32 | done_mesh=0 33 | if [ ${mesh} = 100 ]; then 34 | done_mesh=1 35 | fi 36 | done_build=0 37 | if [ ${build} = 100 ]; then 38 | done_build=1 39 | fi 40 | done_solve=0 41 | if [ ${solve} = 100 ]; then 42 | done_solve=1 43 | fi 44 | done_post=0 45 | if [ ${post} = 100 ]; then 46 | done_post=1 47 | fi 48 | 49 | done_data=0 50 | 51 | cat << EOF > run/${problem_hash}-status.json 52 | { 53 | "status": "running", 54 | "pid": ${feenox_pid}, 55 | "mesh": ${mesh}, 56 | "build": ${build}, 57 | "solve": ${solve}, 58 | "post": ${post}, 59 | "data": ${data}, 60 | "done_mesh": ${done_mesh}, 61 | "done_build": ${done_build}, 62 | "done_solve": ${done_solve}, 63 | "done_post": ${done_post}, 64 | "done_data": ${done_data} 65 | } 66 | EOF 67 | # sync run/${problem_hash}.json 68 | 69 | else 70 | exit 0 71 | fi 72 | -------------------------------------------------------------------------------- /solvers/ccx/solving_status.php: -------------------------------------------------------------------------------- 1 | 51 | -------------------------------------------------------------------------------- /solvers/common.php: -------------------------------------------------------------------------------- 1 | run/{$problem_hash}-check.2", $output, $result); 9 | if ($result == 0) { 10 | exec("../../../../solvers/feenox/solve.sh {$problem} > run/{$problem_hash}-solve.log 2>&1 & echo $! > run/solving.pid"); 11 | $results_meta["status"] = "running"; 12 | suncae_log("{$id} problem running"); 13 | } else { 14 | $results_meta["status"] = "syntax_error"; 15 | suncae_log("{$id} problem syntax error"); 16 | } 17 | 18 | ?> 19 | -------------------------------------------------------------------------------- /solvers/feenox/common.php: -------------------------------------------------------------------------------- 1 | 64 | -------------------------------------------------------------------------------- /solvers/feenox/deps.sh: -------------------------------------------------------------------------------- 1 | #!/bin/false 2 | 3 | feenox_version=1.1.72 4 | 5 | # feenox 6 | echo -n "solvers/feenox... " 7 | feenox_tarball=feenox-${feenox_version}-linux-amd64 8 | if [ $force = 1 ] || [ ! -x bin/feenox ] || [ ! -f deps/${feenox_tarball}.tar.gz ]; then 9 | cd deps 10 | if [ ! -e ${feenox_tarball}.tar.gz ]; then 11 | wget -c https://www.seamplex.com/feenox/dist/linux/${feenox_tarball}.tar.gz 12 | fi 13 | tar xzf ${feenox_tarball}.tar.gz 14 | cp ${feenox_tarball}/bin/feenox ../bin 15 | cp ${feenox_tarball}/bin/fee2ccx ../bin 16 | echo "done" 17 | cd .. 18 | else 19 | echo "already installed" 20 | fi 21 | -------------------------------------------------------------------------------- /solvers/feenox/displacements.fee: -------------------------------------------------------------------------------- 1 | READ_MESH ${1}-1.vtk DIMENSIONS 3 { 2 | READ_FIELD displacements1 AS u 3 | READ_FIELD displacements2 AS v 4 | READ_FIELD displacements3 AS w 5 | READ_FUNCTION sigma 6 | } 7 | 8 | FIND_EXTREMA u(x,y,z)^2+v(x,y,z)^2+w(x,y,z)^2 MAX displ_max2 9 | displ_max = sqrt(displ_max2) 10 | warp_max = if(displ_max > 0, 0.1 * ${2} / displ_max, 1) 11 | 12 | sigma_max = vecmax(vec_sigma) 13 | 14 | OUTPUT_FILE max PATH ${1}-max.json 15 | # TODO: implement PRINTF with FILE 16 | PRINT FILE max "\{" 17 | PRINT FILE max " \"max_displacement\": " displ_max "," 18 | PRINT FILE max " \"max_warp\":" warp_max "," 19 | PRINT FILE max " \"max_sigma\":" sigma_max 20 | PRINT FILE max "\}" 21 | 22 | VECTOR dxv[nodes] 23 | VECTOR dyv[nodes] 24 | VECTOR dzv[nodes] 25 | 26 | dxv[i] = vec_u_x[i] + warp_max*vec_u[i] 27 | dyv[i] = vec_u_y[i] + warp_max*vec_v[i] 28 | dzv[i] = vec_u_z[i] + warp_max*vec_w[i] 29 | 30 | PRINT_VECTOR dxv dyv dzv 31 | 32 | 33 | -------------------------------------------------------------------------------- /solvers/feenox/field.fee: -------------------------------------------------------------------------------- 1 | DEFAULT_ARGUMENT_VALUE 2 sigma 2 | READ_MESH ${1}.vtk DIM 3 READ_FIELD ${2} AS field 3 | 4 | maximum = vecmax(vec_field) 5 | minimum = vecmin(vec_field) 6 | VECTOR normalized[nodes] 7 | normalized[i] = (vec_field[i]-minimum)/(maximum-minimum) 8 | 9 | OUTPUT_FILE max PATH ${1}-max.json 10 | # TODO: implement PRINTF with FILE 11 | PRINT FILE max "\{" 12 | PRINT FILE max " \"max\": " maximum "," 13 | PRINT FILE max " \"min\": " minimum 14 | PRINT FILE max "\}" 15 | 16 | PRINT_VECTOR %.3f normalized 17 | -------------------------------------------------------------------------------- /solvers/feenox/field1.fee: -------------------------------------------------------------------------------- 1 | DEFAULT_ARGUMENT_VALUE 2 sigma 2 | READ_MESH ${1}-1.vtk DIM 3 READ_FIELD ${2} AS field 3 | 4 | maximum = vecmax(vec_field) 5 | VECTOR normalized[nodes] 6 | normalized[i] = vec_field[i]/maximum 7 | 8 | PRINT_VECTOR %.3f normalized 9 | -------------------------------------------------------------------------------- /solvers/feenox/input_initial_heat_conduction.php: -------------------------------------------------------------------------------- 1 | /'"); 8 | $response["plain"] = shell_exec("tail -n+2 case.fee"); 9 | $response["html"] = shell_exec("cat << EOF | ../../../../bin/pandoc -t html --syntax-definition=../../../../solvers/feenox/feenox.xml 10 | ~~~feenox 11 | $(cat case.fee) 12 | ~~~ 13 | EOF"); 14 | 15 | return_back_json($response); 16 | -------------------------------------------------------------------------------- /solvers/feenox/problem_fee_save.php: -------------------------------------------------------------------------------- 1 | &1", $output, $result); 18 | if ($result != 0) { 19 | $response["status"] = "error"; 20 | for ($i = 0; $i < count($output); $i++) { 21 | // this authorization comes from openmpi 22 | if ($output[$i] != "" && strncasecmp($output[$i], "Authorization", 13) != 0) { 23 | if (strncmp("error", $output[$i], 5) == 0) { 24 | $output_exploded = explode(":", $output[$i]); 25 | for ($j = 2; $j < count($output_exploded); $j++) { 26 | $response["error"] .= $output_exploded[$j] ; 27 | } 28 | $response["error"] .= "
"; 29 | } else { 30 | $response["error"] .= $output[$i] . "
"; 31 | } 32 | } 33 | } 34 | } 35 | 36 | return_back_json($response); 37 | -------------------------------------------------------------------------------- /solvers/feenox/problems.php: -------------------------------------------------------------------------------- 1 | run/${problem_hash}.json 25 | { 26 | "status": "running", 27 | "pid": $$ 28 | } 29 | EOF 30 | 31 | # cad=$(yq .cad case.yaml | tr -d \") 32 | cad=$(grep ^cad case.yaml | cut -f2 -d: | tr -d " ") 33 | max_length=$(jq .max_length ../../cads/${cad}/cad.json) 34 | 35 | cp case.fee run/${problem_hash}.fee || exit 2 36 | cd run || exit 3 37 | 38 | # check the syntax 39 | ../../../../../bin/feenox -c ${problem_hash}.fee 1> ${problem_hash}.1 2> ${problem_hash}.2 40 | if [ $? -eq 0 ]; then 41 | # all good! 42 | # see if we have the second-order mesh 43 | if [ ! -e meshes/${mesh_hash}-2.msh ]; then 44 | ../../../../../bin/gmsh -3 meshes/${mesh_hash}.msh -order 2 -o meshes/${mesh_hash}-2.msh > meshes/${mesh_hash}-2.1 45 | fi 46 | 47 | # run 48 | # TODO: time & memory (maybe we can read it from the log) 49 | ../../../../../bin/feenox --progress ${problem_hash}.fee 1> ${problem_hash}.1 2> ${problem_hash}.2 50 | feenox_error=$? 51 | 52 | if [ $feenox_error -eq 0 ]; then 53 | if [ "x${problem_type}" = "xmechanical" ]; then 54 | ../../../../../bin/feenox ../../../../../solvers/feenox/second2first.fee ${problem_hash} ${mesh_hash} 55 | ../../../../../bin/feenox ../../../../../solvers/feenox/displacements.fee ${problem_hash} ${max_length} | tr -s ' \t\n' ' ' > ${problem_hash}-displacements.dat 56 | ../../../../../bin/feenox ../../../../../solvers/feenox/field1.fee ${problem_hash} sigma | tr -s ' \t\n' ' ' > ${problem_hash}-sigma.dat 57 | elif [ "x${problem_type}" = "xheat_conduction" ]; then 58 | ../../../../../bin/feenox ../../../../../solvers/feenox/field.fee ${problem_hash} T | tr -s ' \t\n' ' ' > ${problem_hash}-T.dat 59 | fi 60 | status="success" 61 | else 62 | status="error" 63 | fi 64 | else 65 | status="syntax_error" 66 | fi 67 | 68 | cat << EOF > ${problem_hash}.json 69 | { 70 | "status": "${status}" 71 | } 72 | EOF 73 | 74 | # sync run/meshes/${mesh_hash}.json 75 | rm -f ${dir}/${problem_hash}.pid 76 | -------------------------------------------------------------------------------- /solvers/feenox/solve_status.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -z "${1}" ]; then 4 | problem_hash=($(md5sum case.fee)) 5 | else 6 | problem_hash=${1} 7 | fi 8 | 9 | status=$(jq -r .status run/${problem_hash}.json) || exit 1 10 | if [ "x${status}" == "xrunning" ]; then 11 | feenox_pid=$(jq -r .pid run/${problem_hash}.json) 12 | echo $feenox_pid 13 | if [ -z "$(ps --no-headers --pid ${feenox_pid})" ]; then 14 | echo "solver pid ${feenox_pid} is not running" 15 | echo "TODO: check if it worked or not" 16 | exit 1 17 | fi 18 | 19 | mesh=0 20 | meshfile=$(grep MESH case.fee | awk '{print $4}' | head -n1) 21 | meshname=$(basename ${meshfile} .msh) 22 | if [ -e run/meshes/${meshname}.1 ]; then 23 | mesh=$(grep % run/meshes/${meshname}.1 | tr -d [] | awk '{print $3}' | tr -d % | tail -n1) 24 | fi 25 | 26 | logfile=run/${problem_hash}.1 27 | build=$(grep \\. ${logfile} | tr -d '\n' | wc -c) 28 | solve=$(grep \\- ${logfile} | tr -d '\n' | wc -c) 29 | post=$(grep = ${logfile} | tr -d '\n' | wc -c) 30 | data=50 31 | 32 | done_mesh=0 33 | if [ ${mesh} = 100 ]; then 34 | done_mesh=1 35 | fi 36 | done_build=0 37 | if [ ${build} = 100 ]; then 38 | done_build=1 39 | fi 40 | done_solve=0 41 | if [ ${solve} = 100 ]; then 42 | done_solve=1 43 | fi 44 | done_post=0 45 | if [ ${post} = 100 ]; then 46 | done_post=1 47 | fi 48 | 49 | done_data=0 50 | 51 | cat << EOF > run/${problem_hash}-status.json 52 | { 53 | "status": "running", 54 | "pid": ${feenox_pid}, 55 | "mesh": ${mesh}, 56 | "build": ${build}, 57 | "solve": ${solve}, 58 | "post": ${post}, 59 | "data": ${data}, 60 | "done_mesh": ${done_mesh}, 61 | "done_build": ${done_build}, 62 | "done_solve": ${done_solve}, 63 | "done_post": ${done_post}, 64 | "done_data": ${done_data} 65 | } 66 | EOF 67 | # sync run/${problem_hash}.json 68 | 69 | else 70 | exit 0 71 | fi 72 | -------------------------------------------------------------------------------- /solvers/feenox/solving_relaunch.php: -------------------------------------------------------------------------------- 1 | 51 | -------------------------------------------------------------------------------- /solvers/problems.php: -------------------------------------------------------------------------------- 1 | $problem) { 25 | $keys[$physics] = $physics_name[$physics]; 26 | } 27 | 28 | } else if (isset($problems[$what])) { 29 | 30 | // $keys["none"] = ""; 31 | foreach ($problems[$what] as $index => $problem) { 32 | $keys[$problem] = $problem_name[$problem]; 33 | } 34 | 35 | } else if (isset($solvers[$what])) { 36 | 37 | foreach ($solvers[$what] as $index => $solver) { 38 | $keys[$solver] = $solvers_names[$solver]; 39 | } 40 | } else { 41 | // TODO: 42 | $keys["gmsh"] = "Gmsh"; 43 | 44 | /* 45 | } else if ($what == "fluid") { 46 | 47 | $keys = ["none", "fluid-irrotational", "fluid-incompressible", "fluid-compressible"]; 48 | $values = ["", "Laminar irrotational flow", "Incompressible flow", "Compressible flow"]; 49 | 50 | } else if ($what == "thermal") { 51 | 52 | $keys = ["none", "conduction", "radiation"]; 53 | $values = ["", "Heat conduction", "Radiative heat exchange"]; 54 | 55 | } else if ($what == "electromagnetism") { 56 | 57 | $keys = ["none", "electrostatics", "motor", "antenna"]; 58 | $values = ["", "Electrostatics", "Electrical motors", "Antenna radiation"]; 59 | 60 | } else if ($what == "acoustics") { 61 | 62 | $keys = ["none", "acoustics-linear", "ultrasonics"]; 63 | $values = ["", "Linear acoustics", "Ultrasonics"]; 64 | 65 | } else if ($what == "neutron") { 66 | 67 | $keys = ["none", "neutron-diffusion", "neutron-sn"]; 68 | $values = ["", "Multigroup diffusion", "Multigroup SN"]; 69 | 70 | } else if ($what == "multiphysics") { 71 | 72 | $keys = ["none", "thermo-mechanical", "conjugate-heat", "fluid-structure"]; 73 | $values = ["", "Thermomechanical", "Conjugate heat transfer", "Fluid-structure interaction"]; 74 | */ 75 | } 76 | 77 | $response["keys"] = array(); 78 | $response["values"] = array(); 79 | 80 | foreach ($keys as $key => $value) { 81 | array_push($response["keys"], $key); 82 | array_push($response["values"], $value); 83 | } 84 | 85 | return_back_json($response); 86 | -------------------------------------------------------------------------------- /solvers/sparselizard/LICENSE: -------------------------------------------------------------------------------- 1 | GPLv2+ -------------------------------------------------------------------------------- /solvers/sparselizard/problems.php: -------------------------------------------------------------------------------- 1 | 2 | 37 | 38 | -------------------------------------------------------------------------------- /uxs/faster-than-quick/bootswatch/.gitignore: -------------------------------------------------------------------------------- 1 | bootswatch 2 | package-lock.json 3 | 4 | -------------------------------------------------------------------------------- /uxs/faster-than-quick/bootswatch/_bootswatch.scss: -------------------------------------------------------------------------------- 1 | // CAEplex - based on Flatly 5.0.0-beta2 2 | // Bootswatch 3 | 4 | code { 5 | color: $secondary; 6 | } 7 | 8 | @font-face { 9 | font-family: Carlito; 10 | src: url(fonts/Carlito-Regular.ttf); 11 | } 12 | 13 | @font-face { 14 | font-family: Carlito; 15 | src: url(fonts/Carlito-Bold.ttf); 16 | font-weight: bold; 17 | } 18 | 19 | @font-face { 20 | font-family: Carlito; 21 | src: url(fonts/Carlito-Italic.ttf); 22 | font-style: italic; 23 | } 24 | 25 | @font-face { 26 | font-family: Carlito; 27 | src: url(fonts/Carlito-BoldItalic.ttf); 28 | font-weight: bold; 29 | font-style: italic; 30 | } 31 | 32 | 33 | // Navbar 34 | 35 | .bg-primary { 36 | .navbar-nav .active > .nav-link { 37 | color: $success !important; 38 | } 39 | } 40 | 41 | .bg-dark { 42 | &.navbar-dark .navbar-nav { 43 | .nav-link:focus, 44 | .nav-link:hover, 45 | .active > .nav-link { 46 | color: $primary !important; 47 | } 48 | } 49 | } 50 | 51 | // Buttons 52 | 53 | .btn { 54 | &-secondary, 55 | &-secondary:hover, 56 | &-warning, 57 | &-warning:hover { 58 | color: $white; 59 | } 60 | } 61 | 62 | // Tables 63 | 64 | .table { 65 | &-primary, 66 | &-secondary, 67 | &-success, 68 | &-info, 69 | &-warning, 70 | &-danger { 71 | color: $white; 72 | } 73 | 74 | &-primary { 75 | &, 76 | > th, 77 | > td { 78 | background-color: $primary; 79 | } 80 | } 81 | 82 | &-secondary { 83 | &, 84 | > th, 85 | > td { 86 | background-color: $secondary; 87 | } 88 | } 89 | 90 | &-light { 91 | &, 92 | > th, 93 | > td { 94 | background-color: $light; 95 | } 96 | } 97 | 98 | &-dark { 99 | &, 100 | > th, 101 | > td { 102 | background-color: $dark; 103 | } 104 | } 105 | 106 | &-success { 107 | &, 108 | > th, 109 | > td { 110 | background-color: $success; 111 | } 112 | } 113 | 114 | &-info { 115 | &, 116 | > th, 117 | > td { 118 | background-color: $info; 119 | } 120 | } 121 | 122 | &-danger { 123 | &, 124 | > th, 125 | > td { 126 | background-color: $danger; 127 | } 128 | } 129 | 130 | &-warning { 131 | &, 132 | > th, 133 | > td { 134 | background-color: $warning; 135 | } 136 | } 137 | 138 | &-active { 139 | &, 140 | > th, 141 | > td { 142 | background-color: $table-active-bg; 143 | } 144 | } 145 | 146 | &-hover { 147 | .table-primary:hover { 148 | &, 149 | > th, 150 | > td { 151 | background-color: darken($primary, 5%); 152 | } 153 | } 154 | 155 | .table-secondary:hover { 156 | &, 157 | > th, 158 | > td { 159 | background-color: darken($secondary, 5%); 160 | } 161 | } 162 | 163 | .table-light:hover { 164 | &, 165 | > th, 166 | > td { 167 | background-color: darken($light, 5%); 168 | } 169 | } 170 | 171 | .table-dark:hover { 172 | &, 173 | > th, 174 | > td { 175 | background-color: darken($dark, 5%); 176 | } 177 | } 178 | 179 | .table-success:hover { 180 | &, 181 | > th, 182 | > td { 183 | background-color: darken($success, 5%); 184 | } 185 | } 186 | 187 | .table-info:hover { 188 | &, 189 | > th, 190 | > td { 191 | background-color: darken($info, 5%); 192 | } 193 | } 194 | 195 | .table-danger:hover { 196 | &, 197 | > th, 198 | > td { 199 | background-color: darken($danger, 5%); 200 | } 201 | } 202 | 203 | .table-warning:hover { 204 | &, 205 | > th, 206 | > td { 207 | background-color: darken($warning, 5%); 208 | } 209 | } 210 | 211 | .table-active:hover { 212 | &, > th, > td { 213 | background-color: $table-active-bg; 214 | } 215 | } 216 | 217 | } 218 | } 219 | 220 | // Navs 221 | 222 | .nav-tabs { 223 | .nav-link.active, 224 | .nav-link.active:focus, 225 | .nav-link.active:hover, 226 | .nav-item.open .nav-link, 227 | .nav-item.open .nav-link:focus, 228 | .nav-item.open .nav-link:hover { 229 | color: $primary; 230 | } 231 | } 232 | 233 | .pagination { 234 | a:hover { 235 | text-decoration: none; 236 | } 237 | } 238 | 239 | // Indicators 240 | 241 | .badge { 242 | &-secondary, 243 | &-warning { 244 | color: $white; 245 | } 246 | } 247 | 248 | .alert { 249 | border: none; 250 | color: $white; 251 | 252 | a, 253 | .alert-link { 254 | color: $white; 255 | font-weight: bold; 256 | } 257 | 258 | @each $color, $value in $theme-colors { 259 | &-#{$color} { 260 | @if $enable-gradients { 261 | background: $value linear-gradient(180deg, mix($body-bg, $value, 15%), $value) repeat-x; 262 | } @else { 263 | background-color: $value; 264 | } 265 | } 266 | } 267 | 268 | &-light { 269 | &, 270 | a, 271 | .alert-link { 272 | color: $body-color; 273 | } 274 | } 275 | } 276 | 277 | // Containers 278 | 279 | .modal, 280 | .toast { 281 | .btn-close { 282 | background-image: url("data:image/svg+xml,"); 283 | } 284 | } 285 | -------------------------------------------------------------------------------- /uxs/faster-than-quick/bootswatch/_variables.scss: -------------------------------------------------------------------------------- 1 | // CAEplex - based on Flatly 5.0.0-beta2 2 | // Bootswatch 3 | 4 | $theme: "faster-than-quick" !default; 5 | 6 | // 7 | // Color system 8 | // 9 | 10 | $white: #fff !default; 11 | $gray-100: #f8f9fa !default; 12 | $gray-200: #ecf0f1 !default; 13 | $gray-300: #dee2e6 !default; 14 | $gray-400: #ced4da !default; 15 | $gray-500: #b4bcc2 !default; 16 | $gray-600: #95a5a6 !default; 17 | $gray-700: #7b8a8b !default; 18 | $gray-800: #343a40 !default; 19 | $gray-900: #212529 !default; 20 | $black: #000 !default; 21 | 22 | $blue: #2c3e50 !default; 23 | $indigo: #6610f2 !default; 24 | $purple: #6f42c1 !default; 25 | $pink: #e83e8c !default; 26 | $red: #e74c3c !default; 27 | $orange: #fd7e14 !default; 28 | $yellow: #f39c12 !default; 29 | $green: #18bc9c !default; 30 | $teal: #20c997 !default; 31 | $cyan: #3498db !default; 32 | 33 | $primary: #0f85af !default; 34 | $secondary: #a0a050 !default; 35 | $info: #3b4550 !default; 36 | 37 | $success: $green !default; 38 | $warning: #e58c30 !default; 39 | $danger: $red !default; 40 | $light: $gray-200 !default; 41 | $dark: $gray-700 !default; 42 | 43 | $min-contrast-ratio: 2.15 !default; 44 | 45 | // Links 46 | 47 | $link-color: $primary !default; 48 | 49 | // Fonts 50 | 51 | $font-family-sans-serif: Carlito, Arial, sans-serif !default; 52 | 53 | // $font-size-base: 0.9375rem !default; 54 | $font-size-base: 0.9675rem !default; 55 | 56 | 57 | /* 58 | $h1-font-size: 2.10rem !default; 59 | $h2-font-size: 1.85rem !default; 60 | $h3-font-size: 1.50rem !default; 61 | $h4-font-size: 1.25rem !default; 62 | $h5-font-size: 1.15rem !default; 63 | */ 64 | 65 | // stylelint-disable-next-line value-keyword-case 66 | // $font-family-sans-serif: Lato, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol" !default; 67 | $h1-font-size: 3rem !default; 68 | $h2-font-size: 2.5rem !default; 69 | $h3-font-size: 2rem !default; 70 | 71 | // Tables 72 | 73 | $table-accent-bg: $gray-200 !default; 74 | 75 | // Dropdowns 76 | 77 | $dropdown-link-color: $gray-700 !default; 78 | $dropdown-link-hover-color: $white !default; 79 | $dropdown-link-hover-bg: $primary !default; 80 | 81 | // Navs 82 | 83 | $nav-link-padding-y: .5rem !default; 84 | $nav-link-padding-x: 2rem !default; 85 | $nav-link-disabled-color: $gray-600 !default; 86 | $nav-tabs-border-color: $gray-200 !default; 87 | 88 | // Navbar 89 | 90 | $navbar-padding-y: 1rem !default; 91 | $navbar-dark-color: $white !default; 92 | $navbar-dark-hover-color: $success !default; 93 | 94 | // Pagination 95 | 96 | $pagination-color: $white !default; 97 | $pagination-bg: $success !default; 98 | $pagination-border-width: 0 !default; 99 | $pagination-border-color: transparent !default; 100 | $pagination-hover-color: $white !default; 101 | $pagination-hover-bg: darken($success, 15%) !default; 102 | $pagination-hover-border-color: transparent !default; 103 | $pagination-active-bg: $pagination-hover-bg !default; 104 | $pagination-active-border-color: transparent !default; 105 | $pagination-disabled-color: $gray-200 !default; 106 | $pagination-disabled-bg: lighten($success, 15%) !default; 107 | $pagination-disabled-border-color: transparent !default; 108 | 109 | // List group 110 | 111 | $list-group-hover-bg: $gray-200 !default; 112 | $list-group-disabled-bg: $gray-200 !default; 113 | 114 | // Breadcrumbs 115 | 116 | $breadcrumb-padding-y: .375rem !default; 117 | $breadcrumb-padding-x: .75rem !default; 118 | $breadcrumb-border-radius: .25rem !default; 119 | 120 | // Close 121 | 122 | $close-color: $white !default; 123 | $close-text-shadow: none !default; 124 | 125 | // from bootstrap docs 126 | //$breadcrumb-divider: quote(">"); 127 | $breadcrumb-divider: quote("»"); 128 | /* $breadcrumb-divider: quote("🞂"); */ 129 | /* $brseadcrumb-divider: quote("⇒"); */ 130 | 131 | $btn-close-color: $white !default; 132 | $btn-close-opacity: .4 !default; 133 | $btn-close-hover-opacity: 1 !default; 134 | -------------------------------------------------------------------------------- /uxs/faster-than-quick/bootswatch/make.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -ex 2 | 3 | # https://bootswatch.com/help/#customization 4 | 5 | # * Download the repository: git clone https://github.com/thomaspark/bootswatch.git 6 | # * Install dependencies: npm install 7 | # * Make sure that you have grunt available in the command line. You can install grunt-cli as described on the Grunt Getting Started page. 8 | # * In /dist, modify _variables.scss and _bootswatch.scss in one of the theme directories, or duplicate a theme directory to create a new one. 9 | # * Type grunt swatch:[theme] to build the CSS for a theme, e.g., grunt swatch:flatly for Flatly. Or type grunt swatch to build them all at once. 10 | # * You can run grunt to start a server, watch for any changes to the SASS files, and automatically build a theme and reload it on change. Run grunt server for just the server, and grunt watch for just the watcher. 11 | 12 | if [ ! -d bootswatch ]; then 13 | git clone https://github.com/thomaspark/bootswatch.git 14 | cd bootswatch 15 | else 16 | cd bootswatch 17 | git pull 18 | fi 19 | 20 | if [ -z "$(which npm)" ]; then 21 | sudo apt-get install npm 22 | fi 23 | if [ -z "$(which grunt)" ]; then 24 | sudo apt-get install grunt 25 | fi 26 | 27 | npm install 28 | # npm audit fix 29 | mkdir -p dist/faster-than-quick 30 | cp ../_bootswatch.scss ../_variables.scss dist/faster-than-quick/ 31 | grunt swatch:faster-than-quick 32 | cp dist/faster-than-quick/bootstrap.min.css ../../css/ 33 | 34 | -------------------------------------------------------------------------------- /uxs/faster-than-quick/cad.php: -------------------------------------------------------------------------------- 1 | 5) { 23 | return_error_json("Invalid step"); 24 | } 25 | $next_step = $_POST["next_step"]; 26 | $current_step = (isset($_POST["current_step"])) ? $_POST["current_step"] : 2; 27 | 28 | // if the user is coming from mesh but the mesh options has changed, we have to re-mesh and go back 29 | if ($current_step == 1 && $has_mesh_attempt == false) { 30 | $next_step = 1; 31 | } 32 | 33 | switch ($next_step) { 34 | case 1: 35 | // TODO: per-mesher 36 | chdir($case_dir); 37 | if (file_exists("mesh.geo") == false) { 38 | $geo = fopen("mesh.geo", "w"); 39 | fprintf($geo, "Merge \"../../cads/{$case["cad"]}/cad.xao\";\n"); 40 | fclose($geo); 41 | } 42 | 43 | $response["mesh"] = ($has_mesh) ? $mesh_hash : ""; 44 | if ($has_mesh_attempt == false) { 45 | exec("../../../../bin/gmsh -check mesh.geo 1> run/meshes/{$mesh_hash}-check.1 2> run/meshes/{$mesh_hash}-check.2", $output, $result); 46 | if ($result == 0) { 47 | // https://www.php.net/manual/en/function.exec.php 48 | // https://stackoverflow.com/questions/45953/php-execute-a-background-process 49 | exec("../../../../meshers/gmsh/mesh.sh > run/meshing.log 2>&1 & echo $! > run/meshing.pid"); 50 | $mesh_meta["status"] = "running"; 51 | suncae_log("{$id} mesh running"); 52 | } else { 53 | $mesh_meta["status"] = "syntax_error"; 54 | suncae_log("{$id} mesh syntax error"); 55 | } 56 | file_put_contents("run/meshes/{$mesh_hash}.json", json_encode($mesh_meta)); 57 | } 58 | // if running, go to meshing.php otherwise go to mesh.php, it will know what to show} 59 | // TODO: AND or OR? 60 | $next_step *= (isset($mesh_meta["status"]) && $mesh_meta["status"] != "running") ? (+1) : (-1); 61 | 62 | suncae_log("{$id} change_step {$current_step} -> {$next_step}"); 63 | 64 | break; 65 | 66 | case 3: 67 | $response["results"] = ($has_results) ? $problem_hash : ""; 68 | $response["has_results_attempt"] = $has_results_attempt; 69 | if ($has_results_attempt == false) { 70 | 71 | include("../solvers/{$solver}/change_step_solve.php"); 72 | file_put_contents("run/{$problem_hash}.json", json_encode($results_meta)); 73 | suncae_log("{$id} change_step {$current_step} -> {$next_step}"); 74 | 75 | } 76 | if (isset($results_meta)) { 77 | $next_step *= ($results_meta["status"] != "running") ? (+1) : (-1); 78 | } 79 | break; 80 | } 81 | 82 | $response["step" ] = $next_step; 83 | $response["url"] = "{$step_url[$next_step]}?id={$id}"; 84 | 85 | 86 | return_back_json($response); 87 | -------------------------------------------------------------------------------- /uxs/faster-than-quick/css/.gitignore: -------------------------------------------------------------------------------- 1 | bootstrap-icons.min.css 2 | bootstrap-icons.css 3 | x3dom.css 4 | fonts 5 | katex.min.css 6 | katex.css 7 | -------------------------------------------------------------------------------- /uxs/faster-than-quick/css/ftq.css: -------------------------------------------------------------------------------- 1 | html { 2 | font-size: 1.0rem; 3 | } 4 | 5 | @font-face { 6 | font-family: Carlito; 7 | src: url(fonts/Carlito-Regular.ttf); 8 | } 9 | 10 | @font-face { 11 | font-family: Carlito; 12 | src: url(fonts/Carlito-Bold.ttf); 13 | font-weight: bold; 14 | } 15 | 16 | @font-face { 17 | font-family: Carlito; 18 | src: url(fonts/Carlito-Italic.ttf); 19 | font-style: italic; 20 | } 21 | 22 | @font-face { 23 | font-family: Carlito; 24 | src: url(fonts/Carlito-BoldItalic.ttf); 25 | font-weight: bold; 26 | font-style: italic; 27 | } 28 | 29 | 30 | body { 31 | font-family: Carlito; 32 | } 33 | 34 | /* #cube_canvas { */ 35 | /* position: fixed; */ 36 | /* bottom: 0; */ 37 | /* right·: 0; */ 38 | /* border: 3px solid #73AD21; */ 39 | /* background-color: red; */ 40 | /* } */ 41 | -------------------------------------------------------------------------------- /uxs/faster-than-quick/css/index.html: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seamplex/suncae/0bdb8483ee659a6bbd3b958d2a9b8da87b94125e/uxs/faster-than-quick/css/index.html -------------------------------------------------------------------------------- /uxs/faster-than-quick/deps.sh: -------------------------------------------------------------------------------- 1 | #!/bin/false 2 | 3 | bootstrap_version=5.3.3 4 | bootstrap_icons_version=1.11.3 5 | katex_version=0.16.11 6 | pandoc_version=3.5 7 | 8 | # boostrap (we only need the js, the css comes from bootswatch) 9 | echo -n "uxs/faster-than-quick/bootstrap.js... " 10 | bootstrap_tarball=bootstrap-${bootstrap_version}-dist 11 | if [ $force = 1 ] || [ ! -e uxs/faster-than-quick/js/bootstrap.min.js ] || [ ! -f deps/${bootstrap_tarball}.zip ]; then 12 | cd deps 13 | if [ ! -e ${bootstrap_tarball}.zip ]; then 14 | wget https://github.com/twbs/bootstrap/releases/download/v${bootstrap_version}/${bootstrap_tarball}.zip 15 | fi 16 | if [ ! -d ${bootstrap_tarball} ]; then 17 | unzip ${bootstrap_tarball}.zip 18 | fi 19 | cp ${bootstrap_tarball}/js/bootstrap.min.js ../uxs/faster-than-quick/js 20 | cp ${bootstrap_tarball}/js/bootstrap.bundle.min.js ../uxs/faster-than-quick/js 21 | echo "done" 22 | cd .. 23 | else 24 | echo "already installed" 25 | fi 26 | 27 | 28 | # boostrap icons 29 | echo -n "uxs/faster-than-quick/bootstrap icons... " 30 | bootstrap_icons_tarball=bootstrap-icons-${bootstrap_icons_version} 31 | 32 | if [ $force = 1 ] || [ ! -e uxs/faster-than-quick/css/bootstrap-icons.min.css ] || [ ! -f deps/${bootstrap_icons_tarball}.zip ]; then 33 | cd deps 34 | if [ ! -e ${bootstrap_icons_tarball}.zip ]; then 35 | wget https://github.com/twbs/icons/releases/download/v${bootstrap_icons_version}/${bootstrap_icons_tarball}.zip 36 | fi 37 | if [ ! -d ${bootstrap_icons_tarball} ]; then 38 | unzip ${bootstrap_icons_tarball}.zip 39 | fi 40 | cp ${bootstrap_icons_tarball}/font/bootstrap-icons.min.css ../uxs/faster-than-quick/css 41 | mkdir -p ../uxs/faster-than-quick/css/fonts 42 | cp ${bootstrap_icons_tarball}/font/fonts/bootstrap-icons.woff ../uxs/faster-than-quick/css/fonts 43 | cp ${bootstrap_icons_tarball}/font/fonts/bootstrap-icons.woff2 ../uxs/faster-than-quick/css/fonts 44 | for i in Carlito-Bold Carlito-Italic Carlito-BoldItalic Carlito-Regular; do 45 | wget https://raw.githubusercontent.com/googlefonts/carlito/refs/heads/main/fonts/ttf/${i}.ttf -O ../uxs/faster-than-quick/css/fonts/${i}.ttf 46 | done 47 | echo "done" 48 | cd .. 49 | else 50 | echo "already installed" 51 | fi 52 | 53 | 54 | # katex 55 | echo -n "uxs/faster-than-quick/katex... " 56 | if [ $force = 1 ] || [ ! -e uxs/faster-than-quick/css/katex.min.css ]; then 57 | cd deps 58 | if [ ! -e katex.tar.gz ]; then 59 | wget https://github.com/KaTeX/KaTeX/releases/download/v${katex_version}/katex.tar.gz 60 | fi 61 | if [ ! -d katex ]; then 62 | tar xvzf katex.tar.gz 63 | fi 64 | cp katex/katex.min.css ../uxs/faster-than-quick/css 65 | mkdir -p ../uxs/faster-than-quick/css/fonts 66 | cp katex/fonts/* ../uxs/faster-than-quick/css/fonts 67 | echo "done" 68 | cd .. 69 | else 70 | echo "already installed" 71 | fi 72 | 73 | # pandoc 74 | echo -n "uxs/faster-than-quick/pandoc... " 75 | pandoc_tarball=pandoc-${pandoc_version}-linux-amd64 76 | if [ $force = 1 ] || [ ! -e bin/pandoc ] || [ ! -f deps/${pandoc_tarball}.tar.gz ]; then 77 | cd deps 78 | if [ ! -e ${pandoc_tarball}.tar.gz ]; then 79 | wget https://github.com/jgm/pandoc/releases/download/${pandoc_version}/${pandoc_tarball}.tar.gz 80 | fi 81 | if [ ! -d pandoc-${pandoc_version} ]; then 82 | tar xvzf ${pandoc_tarball}.tar.gz 83 | fi 84 | cp pandoc-${pandoc_version}/bin/pandoc ../bin 85 | echo "done" 86 | cd .. 87 | else 88 | echo "already installed" 89 | fi 90 | 91 | # TODO: gnuplot? 92 | 93 | -------------------------------------------------------------------------------- /uxs/faster-than-quick/expert.php: -------------------------------------------------------------------------------- 1 | 8 | 9 |
Expert zone
10 |
11 | 12 |
13 |
14 |

15 | 18 |

19 |
20 |
21 | TODO: mesh 22 | 23 | TOD: vtk 24 |
25 |
26 |
27 |
28 |

29 | 32 |

33 |
34 |
35 | TODO: show usage 36 | 37 | TODO: clear 38 |
39 |
40 |
41 |
42 |

43 | 46 |

47 |
48 |
49 | 59 | 60 |
61 |
62 | 63 |
64 |
65 | 66 |
67 |
68 | 69 |
70 |
71 | 72 |
73 |
74 | 75 |
76 |
77 | 78 |
79 |
80 |
81 |
82 | 83 | -------------------------------------------------------------------------------- /uxs/faster-than-quick/importers/upload.php: -------------------------------------------------------------------------------- 1 | 6 | 7 | 48 | 49 |
50 | 53 |
54 | 55 | 56 |
57 |
58 |
59 |
60 | Pick or drag-and-drop a single-solid CAD file in STEP format.
61 | If you do not have one, download a sample STEP file here. 62 |
63 |
64 | 65 |
66 | 72 | 73 | 74 | 75 | 76 | 77 |
78 | 79 |
80 | 85 |
86 | -------------------------------------------------------------------------------- /uxs/faster-than-quick/js/.gitignore: -------------------------------------------------------------------------------- 1 | bootstrap*.js 2 | x3dom*.js 3 | -------------------------------------------------------------------------------- /uxs/faster-than-quick/js/heat_conduction.js: -------------------------------------------------------------------------------- 1 | color["bc_1"] = [0.60, 0.30, 0.90]; 2 | color["bc_2"] = [1.00, 0.33, 0.33]; 3 | color["bc_3"] = [0.67, 0.77, 0.37]; 4 | color["bc_4"] = [0.16, 0.83, 1.00]; 5 | color["bc_5"] = [0.40, 1.00, 0.40]; 6 | color["bc_6"] = [1.00, 0.90, 0.50]; 7 | color["bc_7"] = [0.40, 0.80, 0.85]; 8 | color["bc_8"] = [1.00, 0.00, 0.40]; 9 | color["bc_9"] = [0.16, 0.83, 0.00]; 10 | color["bc_10"] = [1.00, 0.40, 0.00]; 11 | 12 | function bc_hide_all(i) { 13 | bootstrap_hide("bc_value_"+i+"_custom"); 14 | bootstrap_hide("bc_value_"+i+"_temperature"); 15 | bootstrap_hide("bc_value_"+i+"_heatflux"); 16 | bootstrap_hide("bc_value_"+i+"_convection"); 17 | } 18 | -------------------------------------------------------------------------------- /uxs/faster-than-quick/js/index.html: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seamplex/suncae/0bdb8483ee659a6bbd3b958d2a9b8da87b94125e/uxs/faster-than-quick/js/index.html -------------------------------------------------------------------------------- /uxs/faster-than-quick/js/mechanical.js: -------------------------------------------------------------------------------- 1 | color["bc_1"] = [0.82, 0.22, 0.68]; 2 | color["bc_2"] = [0.37, 0.85, 0.16]; 3 | color["bc_3"] = [0.93, 0.91, 0.26]; 4 | color["bc_4"] = [0.33, 0.86, 1.00]; 5 | color["bc_5"] = [1.00, 0.66, 0.66]; 6 | color["bc_6"] = [1.00, 0.50, 0.50]; 7 | color["bc_7"] = [0.00, 0.80, 1.00]; 8 | color["bc_8"] = [0.55, 0.37, 0.82]; 9 | color["bc_9"] = [0.00, 1.00, 0.80]; 10 | color["bc_10"] = [1.00, 0.40, 0.00]; 11 | 12 | color["bc_10"] = [0.10, 0.25, 0.50]; 13 | color["bc_11"] = [1.00, 0.80, 0.16]; 14 | color["bc_12"] = [0.75, 0.15, 0.90]; 15 | color["bc_13"] = [0.55, 0.01, 0.22]; 16 | color["bc_14"] = [0.17, 0.38, 0.01]; 17 | color["bc_15"] = [0.78, 0.44, 0.21]; 18 | color["bc_16"] = [1.00, 0.25, 0.50]; 19 | color["bc_17"] = [0.25, 0.83, 0.60]; 20 | color["bc_18"] = [0.35, 0.75, 0.60]; 21 | color["bc_19"] = [0.21, 0.78, 0.78]; 22 | 23 | function bc_hide_all(i) { 24 | bootstrap_hide("bc_value_"+i+"_custom"); 25 | bootstrap_hide("bc_value_"+i+"_fixture"); 26 | bootstrap_hide("bc_value_"+i+"_displacement"); 27 | bootstrap_hide("bc_value_"+i+"_pressure"); 28 | bootstrap_hide("bc_value_"+i+"_force"); 29 | } 30 | 31 | function bc_fixture_update(i) { 32 | string = ""; 33 | if (document.getElementById("bc_"+i+"_fixture_u").checked) { 34 | string += "u=0 "; 35 | } 36 | if (document.getElementById("bc_"+i+"_fixture_v").checked) { 37 | string += "v=0 "; 38 | } 39 | if (document.getElementById("bc_"+i+"_fixture_w").checked) { 40 | string += "w=0 "; 41 | } 42 | 43 | ajax2problem("bc_"+i+"_value" , string); 44 | } 45 | -------------------------------------------------------------------------------- /uxs/faster-than-quick/labels/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | package.json 3 | package-lock.json 4 | -------------------------------------------------------------------------------- /uxs/faster-than-quick/labels/README.md: -------------------------------------------------------------------------------- 1 | Edit `labels.txt` and run 2 | 3 | ``` 4 | ./labels.sh 5 | ``` 6 | 7 | Rembember to install KaTeX: 8 | 9 | ``` 10 | npm install katex 11 | ``` 12 | 13 | -------------------------------------------------------------------------------- /uxs/faster-than-quick/labels/labels.awk: -------------------------------------------------------------------------------- 1 | BEGIN { 2 | print "const katex = require(\"katex\");" 3 | print "console.log(\" ../labels.php 2 | -------------------------------------------------------------------------------- /uxs/faster-than-quick/labels/labels.txt: -------------------------------------------------------------------------------- 1 | u u 2 | v v 3 | w w 4 | u= u= 5 | v= v= 6 | w= w= 7 | p= p= 8 | E= E= 9 | nu= \\nu= 10 | E_x= E_x= 11 | E_y= E_y= 12 | E_z= E_z= 13 | G_x= G_x= 14 | G_y= G_y= 15 | G_z= G_z= 16 | nu_xy= \\nu_{xy}= 17 | nu_xy= \\nu_{xy}= 18 | nu_xy= \\nu_{xy}= 19 | alpha= \\alpha= 20 | alpha_x= \\alpha_x= 21 | alpha_y= \\alpha_y= 22 | alpha_z= \\alpha_z= 23 | mm \\text{mm} 24 | mm2 \\text{mm}^2 25 | mm3 \\text{mm}^3 26 | MPa \\text{MPa} 27 | GPa \\text{GPa} 28 | 1/K \\text{K}^{-1} 29 | maxu \\max{\\|\\mathbf{u}(x,y,z)\\|} 30 | maxsigma \\max{\\sigma(x,y,z)} 31 | xmin x_\\text{min} 32 | xmax x_\\text{max} 33 | ymin y_\\text{min} 34 | ymax y_\\text{max} 35 | zmin z_\\text{min} 36 | zmax z_\\text{max} 37 | T= T= 38 | h= h= 39 | Tref= T_\\text{ref}= 40 | q2= q^{\\prime\\prime}= 41 | K \\text{K} 42 | Wmm-2K \\text{W}\\cdot\\text{mm}^{-2} 43 | Wmm-2K-1 \\text{W}\\cdot\\text{mm}^{-2}\\cdot\\text{K}^{-1} 44 | k= k(x,y,z)= 45 | q3= q^{\\prime\\prime\\prime}(x,y,z)= 46 | Wm-1K-1 \\text{W}\\cdot\\text{m}^{-1}\\cdot\\text{K}^{-1} 47 | Wmm-3 \\text{W}\\cdot\\text{mm}^{-3} 48 | maxT \\max{\\|T(x,y,z)\\|} 49 | minT \\min{\\|T(x,y,z)\\|} 50 | Fx= F_x= 51 | Fy= F_y= 52 | Fz= F_z= 53 | kN \\text{kN} 54 | N \\text{N} 55 | -------------------------------------------------------------------------------- /uxs/faster-than-quick/mesh.php: -------------------------------------------------------------------------------- 1 | 17 | 18 | 19 |
Meshing progress
20 |
21 | 22 |
23 | 24 |
25 |

26 | 29 |

30 |
31 |
32 | 33 | 34 | 35 | 1D : : 0/ edges 36 |
37 |
38 |
39 | 40 | 2D : : 0/ faces 41 |
42 |
43 |
44 | 45 | 3D : : 0/ volumes 46 |
47 |
48 |
49 | 50 | Processing 51 |
52 |
53 |
54 | 55 |
56 |
57 |
58 | Meshing... 59 |
60 |
61 |
62 | 63 |
64 |
65 |
66 | 
67 | 
68 | 
69 | 
70 | 
71 | 
72 |
73 | 74 | 77 | 78 |
79 | 80 |
81 |
82 |
83 | 84 | 85 | 86 |
87 | -------------------------------------------------------------------------------- /uxs/faster-than-quick/preview.php: -------------------------------------------------------------------------------- 1 | 31 | -------------------------------------------------------------------------------- /uxs/faster-than-quick/problem.php: -------------------------------------------------------------------------------- 1 | 30 | 31 |
32 | 33 |
34 | 38 |
39 |
40 | 41 | 80 | 81 | -------------------------------------------------------------------------------- /uxs/faster-than-quick/results.php: -------------------------------------------------------------------------------- 1 | 19 |
20 | The solving process was canceled. 21 | 22 |
23 | 24 | 27 | 30 |
31 | 35 |
36 | 39 | 42 | Got status error but no stderr. 43 | 47 | Not sure what happened. 48 | 53 |
54 | There are no results nor any attempt at getting them. 55 |
56 | 61 |
62 | 72 |
73 | 79 |
Not yet implemented
80 | 86 |
Not yet implemented
87 | 98 | 99 |
100 |
101 |
102 | 
103 | 
104 |
105 | 110 | 111 |
112 |
113 | 117 | 118 | 122 |
123 |
124 | 125 |
"> 126 |
127 |
128 | 129 |
130 |
131 | 132 |
133 |
134 | 135 |
136 |
137 |
138 | 139 | 0) { 141 | ?> 142 | 143 | 146 | 147 | 150 | -------------------------------------------------------------------------------- /uxs/faster-than-quick/results/heat_conduction.php: -------------------------------------------------------------------------------- 1 | 13 | -------------------------------------------------------------------------------- /uxs/faster-than-quick/results/mechanical.php: -------------------------------------------------------------------------------- 1 | 12 | 13 |
Share case
14 |
15 | 16 |
17 |
18 |

19 | 22 |

23 |
24 |
25 | choose email address 26 |
27 |
28 |
29 |
30 |

31 | 34 |

35 |
36 |
37 | Twitter, 38 | LinkedIn, 39 | etc 40 |
41 |
42 |
43 |
44 | 45 | -------------------------------------------------------------------------------- /uxs/faster-than-quick/small_axes.html: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | -------------------------------------------------------------------------------- /uxs/faster-than-quick/solving.php: -------------------------------------------------------------------------------- 1 | 8 | 9 |
Solving progress
10 |
11 | 12 |
13 | 14 |
15 |

16 | 19 |

20 |
21 |
22 | 23 | 24 | 25 | ">Second-order mesh 26 |
" role="progressbar"> 27 |
28 |
29 | 30 | Build 31 |
32 |
33 |
34 | 35 | Solve 36 |
37 |
38 |
39 | 40 | Compute fluxes 41 |
42 |
43 |
44 | 45 | 51 |
52 |
53 |
54 | Solving... 55 |
56 |
57 |
58 | 59 |
60 | 63 | 64 |
65 | 66 |
67 |
68 |
69 | 70 | 71 | 72 |
73 | --------------------------------------------------------------------------------