├── .devcontainer ├── README.md ├── devcontainer.json └── image │ ├── Dockerfile │ ├── README.md │ ├── config │ ├── .wgetrc │ └── texlive.profile │ └── texlive.sh ├── .latexmkrc ├── .vscode ├── extensions.json └── settings.json ├── CHANGELOG.md ├── LICENSE ├── Makefile ├── README.md ├── acp.cls ├── bib ├── README.md ├── bibliography.bib └── glossaries │ ├── abbreviations.bib │ ├── constants.bib │ ├── index │ ├── names.bib │ └── terms.bib │ └── symbols │ ├── greek.bib │ ├── other.bib │ ├── roman.bib │ └── subscripts.bib ├── chapters ├── README.md ├── backmatter.tex ├── frontmatter.tex ├── frontmatter │ ├── abstract.tex │ ├── authorship_declaration.tex │ ├── colophon.tex │ ├── preface.tex │ └── task.tex ├── mainmatter.tex └── mainmatter │ ├── base-features.tex │ ├── code-listings.tex │ ├── floats.tex │ └── usage.tex ├── cookbook.tex ├── data ├── README.md ├── diffuser.csv ├── matlab2tikz_table_example.tex └── matlab2tikz_table_example_data.csv ├── images ├── bitmaps │ ├── README.md │ ├── field.jpg │ ├── readme │ │ ├── backref.png │ │ ├── chem.png │ │ ├── code.png │ │ ├── font-shapes.png │ │ ├── language.png │ │ ├── math-macros.png │ │ ├── math.png │ │ ├── plot-compute.png │ │ ├── plot-csv.png │ │ ├── tables.png │ │ ├── tikz-annotations.png │ │ ├── tikz-diagram.png │ │ └── tikz-libraries.png │ ├── svg_tikz_example.png │ └── svg_tikz_example_debug.png └── vectors │ ├── README.md │ ├── compressor_impeller_isometric.svg │ ├── compressor_rotating_stall.svg │ ├── gas_volume.svg │ ├── gitlab │ └── pdf-git-logo.svg │ ├── logos │ └── matlab_simulink │ │ ├── matlab_object_box.svg │ │ ├── matlab_struct.svg │ │ ├── matlab_table.svg │ │ ├── simulink_algebraic_constraint.svg │ │ ├── simulink_base_workspace.svg │ │ ├── simulink_configuration.svg │ │ ├── simulink_data_dictionary.svg │ │ ├── simulink_library.svg │ │ ├── simulink_library_model.svg │ │ ├── simulink_log_data.svg │ │ ├── simulink_lut.svg │ │ ├── simulink_model.svg │ │ ├── simulink_model_workspace.svg │ │ ├── simulink_referenced_model.svg │ │ └── simulink_step_block.svg │ └── rotor_tip_clearance.svg ├── lib ├── README.md └── example.lua ├── pandoc ├── README.md ├── defaults.yaml ├── metadata.yaml └── promote-headers.lua └── tests ├── Makefile ├── README.md ├── config.yml ├── poetry.lock ├── pyproject.toml └── tests ├── __init__.py ├── conftest.py ├── test_pdfs.py ├── test_self.py └── utils.py /.devcontainer/README.md: -------------------------------------------------------------------------------- 1 | # Remote: Containers for VSCode 2 | 3 | This directory contains all files required to enable [working *inside* of containers](https://code.visualstudio.com/docs/remote/containers) in VSCode. 4 | The entire workspace/IDE will work from *within* the context of a container of an image of your choice. 5 | -------------------------------------------------------------------------------- /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "LaTeX", 3 | // Instead of *building* the accompanying Dockerfile and its whole context, like: 4 | // 5 | // "build": { 6 | // "context": "..", 7 | // "dockerfile": "image/Dockerfile" 8 | // }, 9 | // 10 | // simply download the prepared image the author has already uploaded, based on 11 | // what's found inside the `image/` directory. 12 | // Advantages: 13 | // - build process is slow (downloads from TeX servers), each user doing it every 14 | // time is too much. It can take *hours* in worst-cases 15 | // - build might fail for various reasons 16 | // It is much easier to download the ready-made image. 17 | // Disadvantages: 18 | // - cannot easily iterate on the Docker image, need to go through Docker Hub. 19 | // Recourse: simply change the below to use the *local image temporarily* 20 | // - Upstream image on Docker Hub might not be the latest 21 | "image": "alexpovel/latex", 22 | "customizations": { 23 | "vscode": { 24 | // Set *default* container specific settings.json values on container create. 25 | "settings": { 26 | "terminal.integrated.defaultProfile.linux": "bash" 27 | }, 28 | // Add the IDs of extensions you want installed when the container is created. 29 | // Browse for extensions here: https://marketplace.visualstudio.com/ 30 | // then look for 'Unique Identifier' on the extension's page. 31 | "extensions": [ 32 | "James-Yu.latex-workshop", 33 | "streetsidesoftware.code-spell-checker", 34 | "streetsidesoftware.code-spell-checker-german" 35 | ] 36 | } 37 | }, 38 | "containerEnv": { 39 | // Inside the container, act as though we're in CI. Important for the Makefile. 40 | "CI": "true", 41 | // The base image has this locale: 42 | // $ docker run --rm --entrypoint="locale" alexpovel/latex 43 | // LANG= 44 | // LANGUAGE= 45 | // LC_CTYPE="POSIX" 46 | // LC_NUMERIC="POSIX" 47 | // LC_TIME="POSIX" 48 | // LC_COLLATE="POSIX" 49 | // LC_MONETARY="POSIX" 50 | // LC_MESSAGES="POSIX" 51 | // LC_PAPER="POSIX" 52 | // LC_NAME="POSIX" 53 | // LC_ADDRESS="POSIX" 54 | // LC_TELEPHONE="POSIX" 55 | // LC_MEASUREMENT="POSIX" 56 | // LC_IDENTIFICATION="POSIX" 57 | // LC_ALL= 58 | // *However*, starting this very same container in VSCode's Remote Containers, 59 | // the locale changes to: 60 | // $ locale 61 | // locale: Cannot set LC_CTYPE to default locale: No such file or directory 62 | // locale: Cannot set LC_MESSAGES to default locale: No such file or directory 63 | // locale: Cannot set LC_ALL to default locale: No such file or directory 64 | // LANG=en_US.UTF-8 65 | // LANGUAGE= 66 | // LC_CTYPE="en_US.UTF-8" 67 | // LC_NUMERIC="en_US.UTF-8" 68 | // LC_TIME="en_US.UTF-8" 69 | // LC_COLLATE="en_US.UTF-8" 70 | // LC_MONETARY="en_US.UTF-8" 71 | // LC_MESSAGES="en_US.UTF-8" 72 | // LC_PAPER="en_US.UTF-8" 73 | // LC_NAME="en_US.UTF-8" 74 | // LC_ADDRESS="en_US.UTF-8" 75 | // LC_TELEPHONE="en_US.UTF-8" 76 | // LC_MEASUREMENT="en_US.UTF-8" 77 | // LC_IDENTIFICATION="en_US.UTF-8" 78 | // LC_ALL= 79 | // There's three errors because the container doesn't seem to have the correct 80 | // locale files: 81 | // $ locale -a 82 | // locale: Cannot set LC_CTYPE to default locale: No such file or directory 83 | // locale: Cannot set LC_MESSAGES to default locale: No such file or directory 84 | // locale: Cannot set LC_COLLATE to default locale: No such file or directory 85 | // C 86 | // C.UTF-8 87 | // POSIX 88 | // This leads to `lualatex` erroring out, see also https://tex.stackexchange.com/q/374303/120853 89 | // Using "POSIX" is possible and brings us back to vanilla container locale: 90 | "LC_ALL": "POSIX" 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /.devcontainer/image/config/.wgetrc: -------------------------------------------------------------------------------- 1 | # wget config file 2 | 3 | # TeXLive uses wget. Make wget as robust as possible here. 4 | # Make downloading as robust as possible since TeXLive/TUG servers can be unreliable. 5 | # If we leave downloading to the install script, we cannot influence the parameters 6 | # and it might fail without retrying and for unfortunate reasons at that (like 7 | # failing the entire install an hour in because of one package that failed to 8 | # download). All of this is exacerbated using Docker, since we are building remotely 9 | # on their infrastructure, which is inaccessible. A failure after 8h of queue and 10 | # 2h of build time due to unstable downloads is annoying. 11 | # See also: 12 | # https://www.gnu.org/software/wget/manual/wget.html#Startup-File 13 | # https://superuser.com/a/689340/1144470 14 | # https://www.gnu.org/software/wget/manual/html_node/Sample-Wgetrc.html 15 | 16 | retry_connrefused = on 17 | wait_retry = 120 18 | read_timeout = 20 19 | timeout = 15 20 | tries = 5 21 | 22 | # Setting the following option to `on` can give: 23 | # install-tl: open tlpdb(ftp://tug.org/historic/systems/texlive/2016/tlnet-final/tlpkg/texlive.tlpdb) failed: Inappropriate ioctl for device at tlpkg/TeXLive/TLPDB.pm line 359. 24 | # no-clobber = off 25 | -------------------------------------------------------------------------------- /.devcontainer/image/config/texlive.profile: -------------------------------------------------------------------------------- 1 | # ------------------------------------------------------------------------------- 2 | # TeX Live profile to configure the installation procedure, enabling headless/ 3 | # unattended install. 4 | # For more info, see: https://www.tug.org/texlive/doc/install-tl.html#PROFILES 5 | # ------------------------------------------------------------------------------- 6 | # File has to have LF line endings to work with `install-tl` Perl script! 7 | # ------------------------------------------------------------------------------- 8 | 9 | # We do a manual-ish install, do not use premade scheme: 10 | selected_scheme scheme-custom 11 | 12 | # ------------------------------------------------------------------------------- 13 | # The below directories are the installation destinations. 14 | # An alternative to using the setting here is to set environment variables like 15 | # `TEXLIVE_INSTALL_TEXMFHOME` directly (e.g. in the Dockerfile), but as of late, 16 | # `install-tl` claims to ignore environment variables when installing from a profile 17 | # file ("Environment variables are ignored"): 18 | # https://web.archive.org/web/20201122233159/https://www.tug.org/texlive/doc/install-tl.html#OPTIONS 19 | # So with this profile file guaranteed to work and parallel environment variables 20 | # *maybe* breaking in the future, use this profile file for everything. 21 | # Replace the below environment variables with appropriate values (this is automated 22 | # in the Dockerfile using `envsubst`). 23 | # ------------------------------------------------------------------------------- 24 | 25 | # See: https://www.tug.org/texlive/doc/install-tl.html#ENVIRONMENT-VARIABLES, 26 | # https://tex.stackexchange.com/a/470341/120853. 27 | # IMPORTANT: Put these into the actual designated container's user's home for full 28 | # write access. Otherwise, we run into all sorts of annoying errors, like 29 | # https://tex.stackexchange.com/q/571021/120853. 30 | # The user we run this as is specified in the Dockerfile and inserted into here. 31 | TEXMFHOME /home/${USER}/texmf 32 | TEXMFVAR /home/${USER}/.texlive/texmf-var 33 | TEXMFCONFIG /home/${USER}/.texlive/texmf-config 34 | 35 | # Not required, left at default: 36 | # TEXDIR /usr/local/texlive/ 37 | # TEXMFSYSCONFIG /usr/local/texlive//texmf-config 38 | # TEXMFSYSVAR /usr/local/texlive//texmf-var 39 | # TEXMFLOCAL /usr/local/texlive/texmf-local 40 | # 41 | # ------------------------------------------------------------------------------- 42 | # Collections of packages; for their contents, see 43 | # http://mirror.ctan.org/systems/texlive/tlnet/tlpkg/texlive.tlpdb 44 | # and search for 'name collection-', e.g. 'name collection-basic'. 45 | # At the time of writing, the following encompasses all available collections. 46 | # Only the core ones with very few supported languages are enabled. For example, 47 | # just including 'collection-langjapanese' requires 800MB of space. 48 | # ------------------------------------------------------------------------------- 49 | collection-basic 1 50 | collection-bibtexextra 1 51 | collection-binextra 1 52 | collection-fontsextra 1 53 | collection-fontsrecommended 1 54 | collection-fontutils 1 55 | collection-formatsextra 1 56 | collection-langenglish 1 57 | collection-langeuropean 1 58 | collection-langgerman 1 59 | collection-latex 1 60 | collection-latexextra 1 61 | collection-latexrecommended 1 62 | collection-luatex 1 63 | collection-mathscience 1 64 | collection-pictures 1 65 | collection-plaingeneric 1 66 | collection-publishers 1 67 | collection-xetex 1 68 | # ------------------------------------------------------------------------------- 69 | # Enable the following disabled ones as needed. They are included here so 70 | # everyone can see what is available; as many as possible are disabled, since 71 | # image size matters. The default is aimed at documents in the sciences domain. 72 | # Therefore, everything else is disabled. This includes various languages, so 73 | # activate your missing language here! 74 | # ------------------------------------------------------------------------------- 75 | collection-context 0 76 | collection-games 0 77 | collection-humanities 0 78 | collection-langarabic 0 79 | collection-langchinese 0 80 | collection-langcjk 0 81 | collection-langcyrillic 0 82 | collection-langczechslovak 0 83 | collection-langfrench 0 84 | collection-langgreek 0 85 | collection-langitalian 0 86 | collection-langjapanese 0 87 | collection-langkorean 0 88 | collection-langother 0 89 | collection-langpolish 0 90 | collection-langportuguese 0 91 | collection-langspanish 0 92 | collection-metapost 0 93 | collection-music 0 94 | collection-pstricks 0 95 | collection-texworks 0 96 | collection-wintools 0 97 | # ------------------------------------------------------------------------------- 98 | # Options for TeXLive installation 99 | # ------------------------------------------------------------------------------- 100 | # Create symlinks in standard PATH directories (TeXLive installs into `TEXDIR`, 101 | # see its path above). Instead of manipulating PATH, symlinks to `TEXDIR` are 102 | # created, per default into `/usr/local/bin`. 103 | # This setting is required to find tools! 104 | # WARNING: This seems to only have been introduced in TeXLive 2017, see: 105 | # https://web.archive.org/web/20171213102459/http://www.tug.org/texlive/doc/install-tl.html 106 | # (archives from 2016 and earlier do not mention `adjustpath` on that page). 107 | # 108 | # At the same time, TeXLive 2020 does not seem to respect the set `TEXDIR`, breaking 109 | # installation. However, adjusting the path here automatically works. 110 | # Since older installations will simply ignore this setting, enable it for safety. 111 | instopt_adjustpath 1 112 | # Do not adjust remote CTAN repository; keep the one manually specified. 113 | # Shouldn't matter since the repository is not used after installation/image build. 114 | instopt_adjustrepo 0 115 | # A4 default, not letter format 116 | instopt_letter 0 117 | # No portable installation required 118 | instopt_portable 0 119 | # Required for --shell-escape option, as required by packages, e.g. `svg` 120 | instopt_write18_restricted 1 121 | # ------------------------------------------------------------------------------- 122 | # Some more documentation for the following options at: 123 | # https://tug.org/texlive/doc/tlmgr.html 124 | # ------------------------------------------------------------------------------- 125 | # Autobackup just fills cache, skip; see 126 | # https://tex.stackexchange.com/a/398831/120853 127 | tlpdbopt_autobackup 0 128 | tlpdbopt_backupdir tlpkg/backups 129 | # Create font format files, otherwise they have to be created on the fly each 130 | # time. 131 | tlpdbopt_create_formats 1 132 | # None of the following is required; especially not documentation and source 133 | # files, which fill multiple GBs 134 | tlpdbopt_desktop_integration 0 135 | tlpdbopt_file_assocs 0 136 | tlpdbopt_generate_updmap 0 137 | tlpdbopt_install_docfiles 0 138 | tlpdbopt_install_srcfiles 0 139 | # 140 | # Execute postinstallation code for packages: 141 | tlpdbopt_post_code 1 142 | # Symlink destinations (binaries, documentation, manuals). 143 | # Since symlinking is done manually in the Dockerfile, these are not needed. 144 | # tlpdbopt_sys_bin /usr/local/bin 145 | # tlpdbopt_sys_info /usr/local/share/info 146 | # tlpdbopt_sys_man /usr/local/share/man 147 | -------------------------------------------------------------------------------- /.devcontainer/image/texlive.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Script to fetch `install-tl` script from different sources, depending on argument 4 | # given. 5 | 6 | set -ueo pipefail 7 | 8 | usage() { 9 | echo "Usage: $0 get_installer|install latest|version (YYYY)" 10 | } 11 | 12 | # From: https://stackoverflow.com/a/2990533/11477374 13 | echoerr() { echo "$@" 1>&2; } 14 | 15 | check_path() { 16 | # The following test assumes the most basic program, `tex`, is present, see also 17 | # https://www.tug.org/texlive/doc/texlive-en/texlive-en.html#x1-380003.5 18 | echo "Checking PATH and installation..." 19 | if tex --version 20 | then 21 | echo "PATH and installation seem OK, exiting with success." 22 | exit 0 23 | else 24 | echoerr "PATH or installation unhealthy, further action required..." 25 | fi 26 | } 27 | 28 | if [[ $# != 2 ]]; then 29 | echoerr "Unsuitable number of arguments given." 30 | echoerr "Got arguments: $*" 31 | usage 32 | # From /usr/include/sysexits.h 33 | exit 64 34 | fi 35 | 36 | # Bind CLI arguments to explicit names: 37 | ACTION=${1} 38 | VERSION=${2} 39 | 40 | # Download the `install-tl` script from the `tlnet-final` subdirectory, NOT 41 | # from the parent directory. The latter contains an outdated, non-final `install-tl` 42 | # script, causing this exact problem: 43 | # https://tug.org/pipermail/tex-live/2017-June/040376.html 44 | HISTORIC_URL="ftp://tug.org/historic/systems/texlive/${VERSION}/tlnet-final" 45 | REGULAR_URL="http://mirror.ctan.org/systems/texlive/tlnet" 46 | 47 | case ${ACTION} in 48 | "get_installer") 49 | if [[ ${VERSION} == "latest" ]] 50 | then 51 | # Get from default, current repository 52 | GET_URL="${REGULAR_URL}/${TL_INSTALL_ARCHIVE}" 53 | else 54 | # Get from historic repository 55 | GET_URL="${HISTORIC_URL}/${TL_INSTALL_ARCHIVE}" 56 | fi 57 | wget "$GET_URL" 58 | ;; 59 | "install") 60 | if [[ ${VERSION} == "latest" ]] 61 | then 62 | # Install using default, current repository. 63 | # Install process/script documentation is here: 64 | # https://www.tug.org/texlive/doc/texlive-en/texlive-en.html 65 | perl install-tl \ 66 | --profile="$TL_PROFILE" 67 | else 68 | # Install using historic repository (`install-tl` script and repository 69 | # versions need to match) 70 | perl install-tl \ 71 | --profile="$TL_PROFILE" \ 72 | --repository="$HISTORIC_URL" 73 | fi 74 | 75 | # If automatic `install-tl` process has already adjusted PATH, we are happy. 76 | check_path 77 | echo "install-tl procedure did not adjust PATH automatically, trying other options..." 78 | 79 | # `\d` class doesn't exist for basic `grep`, use `0-9`, which is much more 80 | # portable. Finding the initial dir is very fast, but looking through everything 81 | # else afterwards might take a while. Therefore, print and quit after first result. 82 | # Path example: `/usr/local/texlive/2018/bin/x86_64-linux` 83 | TEXLIVE_BIN_DIR=$(find / -type d -regextype grep -regex '.*/texlive/[0-9]\{4\}/bin/.*' -print -quit) 84 | 85 | # -z test: string zero length? 86 | if [ -z "$TEXLIVE_BIN_DIR" ] 87 | then 88 | echoerr "Expected TeXLive installation dir not found and TeXLive installation did not modify PATH automatically." 89 | echoerr "Exiting." 90 | exit 1 91 | fi 92 | 93 | echo "Found TeXLive binaries at $TEXLIVE_BIN_DIR" 94 | echo "Trying native TeXLive symlinking using tlmgr..." 95 | 96 | # To my amazement, `tlmgr path add` can fail but still link successfully. So 97 | # check if PATH is OK despite that command failing. 98 | "$TEXLIVE_BIN_DIR"/tlmgr path add || \ 99 | echoerr "Command borked, checking if it worked regardless..." 100 | check_path 101 | echoerr "Symlinking using tlmgr did not succeed, trying manual linking..." 102 | 103 | SYMLINK_DESTINATION="/usr/local/bin" 104 | 105 | # "String contains", see: https://stackoverflow.com/a/229606/11477374 106 | if [[ ! ${PATH} == *${SYMLINK_DESTINATION}* ]] 107 | then 108 | # Should never get here, but make sure. 109 | echoerr "Symlink destination ${SYMLINK_DESTINATION} not in PATH (${PATH}), exiting." 110 | exit 1 111 | fi 112 | 113 | echo "Symlinking TeXLive binaries in ${TEXLIVE_BIN_DIR}" 114 | echo "to a directory (${SYMLINK_DESTINATION}) found on PATH (${PATH})" 115 | 116 | # Notice the slash and wildcard. 117 | ln \ 118 | --symbolic \ 119 | --verbose \ 120 | --target-directory="$SYMLINK_DESTINATION" \ 121 | "$TEXLIVE_BIN_DIR"/* 122 | 123 | check_path 124 | 125 | echoerr "All attempts failed, exiting." 126 | exit 1 127 | ;; 128 | *) 129 | echoerr "Input not understood." 130 | usage 131 | # From /usr/include/sysexits.h 132 | exit 64 133 | esac 134 | -------------------------------------------------------------------------------- /.latexmkrc: -------------------------------------------------------------------------------- 1 | #!/bin/env perl 2 | 3 | # This file contains instructions and configurations for the `latexmk` program. 4 | # That program is somewhat like `make`, but tailored to LaTeX. 5 | # LaTeX has a distinct characteristic of regularly requiring *multiple runs* of 6 | # the same program (e.g. `lualatex`) before the build is finished. 7 | # It's a *multi-pass* system. 8 | # In the intermediary runs, latex generates auxiliary files responsible for resolving 9 | # references, links, tables of content etc. 10 | 11 | # `latexmk` knows about these dependencies (otherwise we tell it in this very config 12 | # file, see below), detects these and runs latex (and other, outside programs) 13 | # accordingly. 14 | 15 | # Now, why do we need *both* `latexmk` and `make`? 16 | # Both automate builds. 17 | 18 | # `latexmk` is not powerful enough to cover all use cases. 19 | # `make` is more general and more suitable to be integrated in CI. 20 | # For our latex needs, `make` basically only delegates to `latexmk`. 21 | # We **do not** call e.g. `lualatex` multiple times manually from `make`: 22 | # this logic is left to `latexmk` and `.latexmkrc`. 23 | # However, `make` can also do much more, e.g. cover `pandoc`, clean-up operations etc. 24 | # Therefore, `make` and `latexmkrc` *together* are just super powerful and useful. 25 | 26 | 27 | # The shebang at the top is only to get syntax highlighting right across GitLab, 28 | # GitHub and IDEs. 29 | # This file is not meant to be run, but read by `latexmk`. 30 | 31 | # ====================================================================================== 32 | # Perl `latexmk` configuration file 33 | # ====================================================================================== 34 | 35 | # ====================================================================================== 36 | # PDF Generation/Building/Compilation 37 | # ====================================================================================== 38 | 39 | # PDF-generating modes are: 40 | # 1: pdflatex, as specified by $pdflatex variable (still largely in use) 41 | # 2: postscript conversion, as specified by the $ps2pdf variable (useless) 42 | # 3: dvi conversion, as specified by the $dvipdf variable (useless) 43 | # 4: lualatex, as specified by the $lualatex variable (best) 44 | # 5: xelatex, as specified by the $xelatex variable (second best) 45 | $pdf_mode = 4; 46 | 47 | # Treat undefined references and citations as well as multiply defined references as 48 | # ERRORS instead of WARNINGS. 49 | # This is only checked in the *last* run, since naturally, there are undefined references 50 | # in initial runs. 51 | # This setting is potentially annoying when debugging/editing, but highly desirable 52 | # in the CI pipeline, where such a warning should result in a failed pipeline, since the 53 | # final document is incomplete/corrupted. 54 | # 55 | # However, I could not eradicate all warnings, so that `latexmk` currently fails with 56 | # this option enabled. 57 | # Specifically, `microtype` fails together with `fontawesome`/`fontawesome5`, see: 58 | # https://tex.stackexchange.com/a/547514/120853 59 | # The fix in that answer did not help. 60 | # Setting `verbose=silent` to mute `microtype` warnings did not work. 61 | # Switching between `fontawesome` and `fontawesome5` did not help. 62 | $warnings_as_errors = 0; 63 | 64 | # Show used CPU time. Looks like: https://tex.stackexchange.com/a/312224/120853 65 | $show_time = 1; 66 | 67 | # Default is 5; we seem to need more owed to the complexity of the document. 68 | # Actual documents probably don't need this many since they won't use all features, 69 | # plus won't be compiling from cold each time. 70 | $max_repeat=7; 71 | 72 | # --shell-escape option (execution of code outside of latex) is required for the 73 | #'svg' package. 74 | # It converts raw SVG files to the PDF+PDF_TEX combo using InkScape. 75 | # 76 | # SyncTeX allows to jump between source (code) and output (PDF) in IDEs with support 77 | # (many have it). A value of `1` is enabled (gzipped), `-1` is enabled but uncompressed, 78 | # `0` is off. 79 | # Testing in VSCode w/ LaTeX Workshop only worked for the compressed version. 80 | # Adjust this as needed. Of course, only relevant for local use, no effect on a remote 81 | # CI pipeline (except for slower compilation, probably). 82 | # 83 | # %O and %S will forward Options and the Source file, respectively, given to latexmk. 84 | # 85 | # `set_tex_cmds` applies to all *latex commands (latex, xelatex, lualatex, ...), so 86 | # no need to specify these each. This allows to simply change `$pdf_mode` to get a 87 | # different engine. Check if this works with `latexmk --commands`. 88 | set_tex_cmds("--shell-escape --synctex=1 %O %S"); 89 | 90 | # option 2 is same as 1 (run biber when necessary), but also deletes the 91 | # regeneratable bbl-file in a clenaup (`latexmk -c`). Do not use if original 92 | # bib file is not available! 93 | $bibtex_use = 2; # default: 1 94 | 95 | # Change default `biber` call, help catch errors faster/clearer. See 96 | # https://web.archive.org/web/20200526101657/https://www.semipol.de/2018/06/12/latex-best-practices.html#database-entries 97 | $biber = "biber --validate-datamodel %O %S"; 98 | 99 | # ====================================================================================== 100 | # Auxiliary Files 101 | # ====================================================================================== 102 | 103 | # Let latexmk know about generated files, so they can be used to detect if a 104 | # rerun is required, or be deleted in a cleanup. 105 | # loe: List of Examples (KOMAScript) 106 | # lol: List of Listings (`listings` and `minted` packages) 107 | # run.xml: biber runs 108 | # glg: glossaries log 109 | # glstex: generated from glossaries-extra 110 | push @generated_exts, 'loe', 'lol', 'lor', 'run.xml', 'glg', 'glstex'; 111 | 112 | # Also delete the *.glstex files from package glossaries-extra. Problem is, 113 | # that that package generates files of the form "basename-digit.glstex" if 114 | # multiple glossaries are present. Latexmk looks for "basename.glstex" and so 115 | # does not find those. For that purpose, use wildcard. 116 | # Also delete files generated by gnuplot/pgfplots contour plots 117 | # (.dat, .script, .table). 118 | $clean_ext = "%R-*.glstex %R_contourtmp*.*"; 119 | 120 | # ====================================================================================== 121 | # bib2gls as a custom dependency 122 | # ====================================================================================== 123 | 124 | # Grabbed from latexmk CTAN distribution: 125 | # Implementing glossary with bib2gls and glossaries-extra, with the 126 | # log file (.glg) analyzed to get dependence on a .bib file. 127 | # !!! ONLY WORKS WITH VERSION 4.54 or higher of latexmk 128 | 129 | # Add custom dependency. 130 | # latexmk checks whether a file with ending as given in the 2nd 131 | # argument exists ('toextension'). If yes, check if file with 132 | # ending as in first argument ('fromextension') exists. If yes, 133 | # run subroutine as given in fourth argument. 134 | # Third argument is whether file MUST exist. If 0, no action taken. 135 | add_cus_dep('aux', 'glstex', 0, 'run_bib2gls'); 136 | 137 | # PERL subroutine. $_[0] is the argument (filename in this case). 138 | # File from author from here: https://tex.stackexchange.com/a/401979/120853 139 | sub run_bib2gls { 140 | if ( $silent ) { 141 | # my $ret = system "bib2gls --silent --group '$_[0]'"; # Original version 142 | my $ret = system "bib2gls --silent --group $_[0]"; # Runs in PowerShell 143 | } else { 144 | # my $ret = system "bib2gls --group '$_[0]'"; # Original version 145 | my $ret = system "bib2gls --group $_[0]"; # Runs in PowerShell 146 | }; 147 | 148 | my ($base, $path) = fileparse( $_[0] ); 149 | if ($path && -e "$base.glstex") { 150 | rename "$base.glstex", "$path$base.glstex"; 151 | } 152 | 153 | # Analyze log file. 154 | local *LOG; 155 | $LOG = "$_[0].glg"; 156 | if (!$ret && -e $LOG) { 157 | open LOG, "<$LOG"; 158 | while () { 159 | if (/^Reading (.*\.bib)\s$/) { 160 | rdb_ensure_file( $rule, $1 ); 161 | } 162 | } 163 | close LOG; 164 | } 165 | return $ret; 166 | } 167 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | // See https://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations. 3 | // Extension identifier format: ${publisher}.${name}. Example: vscode.csharp 4 | // List of extensions which should be recommended for users of this workspace. 5 | "recommendations": [ 6 | "ms-vscode-remote.remote-containers", 7 | "James-Yu.latex-workshop" 8 | ], 9 | // List of extensions recommended by VS Code that should not be recommended for users of this workspace. 10 | "unwantedRecommendations": [] 11 | } -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "latex-workshop.latex.recipes": [ 3 | { 4 | "name": "latexmk", 5 | "tools": [ 6 | "latexmk" 7 | ] 8 | }, 9 | { 10 | "name": "lualatex", 11 | "tools": [ 12 | "lualatex" 13 | ] 14 | } 15 | ], 16 | "latex-workshop.latex.tools": [ 17 | { 18 | "name": "lualatex", 19 | "command": "lualatex", 20 | "args": [ 21 | "--shell-escape", 22 | "--synctex=1", 23 | "--recorder", 24 | "%DOC%" 25 | ] 26 | }, 27 | { 28 | "name": "latexmk", 29 | "command": "latexmk", 30 | "args": [ 31 | // latexmk doesn't need a file argument, but provide it to avoid running 32 | // on *all* found tex files 33 | "%DOC%" 34 | ] 35 | } 36 | ], 37 | "latex-workshop.latex.recipe.default": "first", 38 | "latex-workshop.linting.chktex.enabled": true, 39 | "latex-workshop.linting.run": "onSave", 40 | "latex-workshop.latex.autoBuild.run": "never", 41 | } 42 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 6 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 7 | 8 | ## [Unreleased] 9 | 10 | ## [5.0.0] - 2022-05-11 11 | 12 | ### Added 13 | 14 | - GitHub Actions configuration (b847c85) 15 | 16 | This is supposed to replace the GitLab config. 17 | 18 | ### Changed 19 | 20 | - GitLab references to point to GitHub instead (7a33ee3) 21 | - Updated Python test suite from 3.7 to 3.10 (0733c83) 22 | - Simplified `polyglossia` language loading (053b87d) 23 | - Switched VSCode Remote Containers config from building to downloading image (4efd364). 24 | 25 | When new users first use this template, it is extremely frustrating for them to have to *build* the entire Docker image from scratch themselves, which can take very long. 26 | Simply download the existing one from DockerHub, which is much faster. 27 | 28 | ### Removed 29 | 30 | - GitLab-specific content (config files, documentation, ...) (7a33ee3) 31 | - Deprecated `chemmacros` `usechemmodule` macro (0909097) 32 | - Profanity check in PDF test (0733c83) 33 | 34 | ## [4.0.0] - 2021-10-18 35 | 36 | ### Added 37 | 38 | - `matlab2tikz` improved alternative showcase using `pgfplots` (0910bca) 39 | - Important badges of high importance for important information (d19b8d9) 40 | - Hint on `parskip` usage to remove paragraph indentation in favor of vertical space (a292f6b) 41 | - Support for *Acronyms* glossary title localization (86c0be1) 42 | - New package for tables, `tabularray` (6825ff9, 480b400) 43 | - Docker image source (merged in c584129) 44 | - Additional math/unit font examples (2e3a582) 45 | 46 | ### Fixed 47 | 48 | - Display of dimensionless quantities (5f8dc71) 49 | - Tabular vertical excess white space (e5f983e) 50 | 51 | ### Changed 52 | 53 | - usage of `chemmacros` over `chemformula` (e379fa9, c26d613) 54 | - `siunitx` settings and usage to support [major version 3](https://github.com/josephwright/siunitx/blob/v3.0.0/CHANGELOG.md#v300) (bb931a9, 4fc2caf, 6747a36, 190bc89, e83902a, 82977ce) 55 | - Docker image source (b50eb6f, f10005e, 548dca9, a8fff45, afa8407, 3a0b4f0, a57a4ec) 56 | - massive simplification/moving of README content (f8f4d3f, 2925463, 2840312, a99df09, bcb4d69) 57 | 58 | ### Removed 59 | 60 | - LaTeX Workshop automatic compilation on save (6b0d313) 61 | - Old files (6fbdc2e, 04eb8fe, 096331c, b37316d, cdc285d) 62 | 63 | ## [3.1.0] - 2021-03-12 64 | 65 | ### Added 66 | 67 | - Toggle for inclusion of glossaries in the Table of Contents (ToC) (5c23bd0) 68 | - Example for an appendix (d4a42ce) 69 | - Translations for code listings in references, lists, captions (6148d55) 70 | - ARCHITECTURE document (840eff8) 71 | - Example for a `longtabu` (multi-page table) displaying random data generated by custom Lua script (9e89214) 72 | - Section on alternative ways to compile (f2d550d) 73 | - Configuration and ideal setup for working with this template inside Visual Studio Code, using its native container development environment (38a0bb2) 74 | - Example for a new unit specification using `siunitx` (7a2d0d0) 75 | 76 | ### Changed 77 | 78 | - Switched bibliography generation from vanilla Zotero to Zotero with its excellent **Better Bibtex** addon (a05f5f4) 79 | - Fixed biblatex fields according to `biber --validate-datamodel` validation (eb068bd) 80 | - Fixed using a system directory for `pandoc`, which required `sudo` privileges (no just user privileges) (d8f4c1c) 81 | 82 | ### Removed 83 | 84 | - TeXGyrePagella font files: use those included in the TeX distribution itself (d74c2d9) 85 | - Trailing whitespaces (WOW!) (d766fb6) 86 | 87 | ## [3.0.0] - 2021-02-03 88 | 89 | ### Added 90 | 91 | - Option to suppress printing of pages list in the glossaries (b75d3d1) 92 | - GitLab description templates (7038798) 93 | 94 | ### Changed 95 | 96 | - Syntax highlighting now uses `minted` instead of `listings`, a backwards-incompatible change (19fbd87) 97 | - Documentation now stresses Docker usage over manual "labour" (6843a2b) 98 | 99 | ### Removed 100 | 101 | - Previous, custom-made `listings` language definitions; these are covered much better by `pygments`, aka `minted` (19fbd87) 102 | 103 | ## [2.0.0] - 2020-11-11 104 | 105 | ### Added 106 | 107 | - Python-based tests for the produced PDFs (1746e4e). 108 | This allows the user to automatically run a test suite against the produced PDFs, 109 | for example checking for page count, metadata and much more. 110 | - Makefiles for the [root](Makefile) and [tests](tests/Makefile) directories, while 111 | also swapping all CI routines over to use `make` (b4a9881). 112 | This allows for local as well as CI use using the same commands, and reduces coupling 113 | with the CI engine. 114 | - Caching of files in CI, for much faster pipelines (while introducing some issues) (28aea76). 115 | - Showcase and fixing of `\abs` macro for absolute values (4d0c6ff, bb11b72). 116 | 117 | ### Changed 118 | 119 | - Git metadata display in the colophon (7c59cbe). 120 | 121 | ## [1.2.0] - 2020-10-29 122 | 123 | ### Added 124 | 125 | - Showcase for multiple lines with contours in TikZ overlay (ae4ad39) 126 | - Hint for the `glossaries-extra` *Beginner's Guide* (d8b7fb4) 127 | - Written permission (license) to use and distribute the [Fontin Sans](https://www.fontsquirrel.com/fonts/fontin-sans) 128 | font (cf79ee4) 129 | - Summary for font licenses (0372475) 130 | - Contributing guideline (56c4eac) 131 | - README info on git and Docker (fa228b7) 132 | - A `matlab2tikz` exported plot example (86dac19, c3e9b09) 133 | - `YAML`-based configs for pandoc (cb39706) 134 | - Proper check for the used TeX engine (de2a293) 135 | 136 | ### Changed 137 | 138 | - Fontawesome implementation, away from the `fontawesome` package to the more 139 | modern `fontawesome5` (8df784e) 140 | - Insertion of git metadata into the document (PDF metadata or into the printed text 141 | directly): now based on Lua (6d0cd7e) 142 | - Also adjusted the README according to the new Lua implementation (ed946b8) 143 | 144 | ## [1.1.1] - 2020-06-09 145 | 146 | ### Added 147 | 148 | - Entry `Mach` in `names.bib` (d0d5683). Was previously removed, but is required. 149 | 150 | ## [1.1.0] - 2020-06-09 151 | 152 | ### Added 153 | 154 | - Added `bib` file entries for the built-in math macros (f1803d3b): 155 | - `\mean` 156 | - `\logmean` 157 | - `\flow` 158 | - `\difference` 159 | - `\nablaoperator` 160 | - `\vect` 161 | - `\deriv` 162 | - `\fracderiv` 163 | - `\timederiv` 164 | - `\posderiv` 165 | - New tabular showcasing those built-in math macros (119fce11) 166 | - New tabular showcasing the built-in glossary commands (0e7ed5a9): 167 | - `\idx` 168 | - `\name` 169 | - `\sym` 170 | - `\sub` 171 | - `\abb` 172 | - `\cons` 173 | - Added sample entries for the *Terms* index (6ca2670b) 174 | 175 | ### Removed 176 | 177 | - Unused entry `Mach` in `names.bib` (c000d4ec) 178 | 179 | ## [1.0.0] - 2020-04-22 180 | 181 | ### Added 182 | 183 | - Initial release 184 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Alex Povel 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # LaTeX Cookbook 2 | 3 | [![Download PDF](https://img.shields.io/badge/Download-PDF-blue.svg)][download] 4 | 5 | This repo contains a [LaTeX document](cookbook.tex), usable as a cookbook (different "recipes" to achieve various things in LaTeX) as well as as a template. 6 | The resulting PDF covers LaTeX-specific topics and instructions on compiling the LaTeX source. 7 | 8 | See the [releases page](https://github.com/alexpovel/latex-cookbook/releases) for more downloads. 9 | 10 | > [!IMPORTANT] 11 | > This project is not archived, and [issues are still 12 | > addressed](https://github.com/alexpovel/latex-cookbook/issues/17). However, the 13 | > document is regarded as "done" and no new feature development actively happens. As LaTeX is a glacially slow-moving target, the document 14 | > should be useful, valid and buildable for many years to come still. 15 | > 16 | > There is a [fork 17 | > maintained](https://collaborating.tuhh.de/m21/public/theses/itt-latex-template) by 18 | > former coworkers of the author, at the research institute this template originated 19 | > from as well. Active development is still happening there. 20 | 21 | ## Getting started 22 | 23 | After installing [Docker](https://www.docker.com/) (and git), building works out of the 24 | box: 25 | 26 | - Bash: 27 | 28 | ```console 29 | $ git clone git@github.com:alexpovel/latex-cookbook.git 30 | $ cd latex-cookbook 31 | $ docker run --rm --volume $(pwd):/tex alexpovel/latex 32 | $ xdg-open cookbook.pdf 33 | ``` 34 | 35 | - PowerShell: 36 | 37 | ```powershell 38 | PS> git clone git@github.com:alexpovel/latex-cookbook.git 39 | PS> cd latex-cookbook 40 | PS> docker run --rm --volume ${PWD}:/tex alexpovel/latex 41 | PS> Invoke-Item cookbook.pdf 42 | ``` 43 | 44 | The [entrypoint](https://docs.docker.com/engine/reference/builder/#entrypoint) is 45 | [`latexmk`](https://ctan.org/pkg/latexmk?lang=en), which when given no arguments (as 46 | done here) runs on all found `*.tex` files, which in this case is only the root's [main 47 | file](./cookbook.tex). 48 | 49 | > [!NOTE] 50 | > Should this fail to compile (this is a bug, please report!), feel free to try other 51 | > images. When `alexpovel/latex` was built, 52 | > [`texlive/texlive`](https://hub.docker.com/r/texlive/texlive) did not exist yet. 53 | > **That image is strongly recommended**, as it is actively maintained by the actual 54 | > authors of TeXLive. If tools are missing, like `inkscape`, build your own image `FROM 55 | > texlive/texlive`, then install required software. 56 | > 57 | > Alternatively, there is [a 58 | > fork](https://collaborating.tuhh.de/m21/public/theses/latex_dockerfile) for the image 59 | > as well, accompanying the [template 60 | > fork](https://collaborating.tuhh.de/m21/public/theses/itt-latex-template). 61 | 62 | ## Features 63 | 64 | The [PDF itself][download] has much more to say on this and is meant to speak for itself, visually. 65 | The following is simply a brief overview of the features contained in this repo. 66 | 67 | ### Tooling 68 | 69 | - accompanying [Docker image](.devcontainer/image/Dockerfile), usable locally and in CI/CD, guaranteeing compilation success without interfering with your local installation. 70 | In fact, using Docker (containerization in general), no LaTeX installation is required at all. 71 | - accompanying Visual Studio Code [environment configuration](.devcontainer/devcontainer.json). 72 | 73 | If you open this repository in [Visual Studio Code](https://code.visualstudio.com/), it should automatically put you into the correct Docker container environment for development, and just work™. 74 | See [here](.devcontainer/README.md) for more info. 75 | - in the image, [`pandoc`](https://pandoc.org/) is available with the [Eisvogel](https://github.com/Wandmalfarbe/pandoc-latex-template) template, allowing beautiful PDFs to be generated from Markdown (like this README: download it from the latest [Actions artifacts](https://github.com/alexpovel/latex-cookbook/actions); it currently looks lackluster because this README is mainly PNGs) 76 | - [tests](tests/config.yml) for your PDF, using Python to ensure some (basic) properties of your output adhere to expectations 77 | - a [Makefile](Makefile) to facilitate ease of use and platform independence (commands like `make file.pdf` work locally as well as in CI pipelines) 78 | 79 | ### LaTeX-specific 80 | 81 | - full Unicode support through `lualatex`, the [successor](https://en.wikipedia.org/wiki/LuaTeX) to the obsolete `pdflatex`. 82 | This also affords beautiful font typesetting through [`unicode-math`](https://ctan.org/pkg/unicode-math). 83 | High-quality fonts like [TeX Gyre Pagella](https://ctan.org/pkg/tex-gyre-pagella) have all desirable font shapes available: 84 | ![font-shapes](images/bitmaps/readme/font-shapes.png) 85 | - automatic compilation using [`latexmk`](.latexmkrc), ensuring the PDF is built fully, running all steps necessary (generation of the bibliography, glossaries, ...) automatically as needed 86 | - comprehensive support for: 87 | - generating [indices](bib/glossaries/index/), 88 | - typesetting and displaying [symbols](bib/glossaries/symbols/) in an automatically generated nomenclature, 89 | - [acronyms and abbreviations](bib/glossaries/abbreviations.bib), as well as 90 | - [mathematical constants](bib/glossaries/constants.bib), 91 | 92 | made possible through [`glossaries-extra`](https://ctan.org/pkg/glossaries-extra). 93 | - structured and commented source code, explaining rationales and providing context 94 | - showcasing plotting and data display (floats): 95 | - computing more complicated plots (in this example, a contour plot) *directly in LaTeX*, with no explicit outside tools used ([`gnuplot`](http://www.gnuplot.info/) is used by LaTeX in the background): 96 | 97 | ![plot-compute](images/bitmaps/readme/plot-compute.png) 98 | - ingesting a CSV directly, and plotting it (so we can skip [`matlab2tikz`](https://www.mathworks.com/matlabcentral/fileexchange/22022-matlab2tikz-matlab2tikz) etc.). 99 | The below style is inspired by [Tufte](https://www.edwardtufte.com/tufte/): 100 | 101 | ![plot-csv](images/bitmaps/readme/plot-csv.png) 102 | - typesetting more complex tables, with footnotes, decimal alignment and more: 103 | 104 | ![table](images/bitmaps/readme/tables.png) 105 | - using tikz: 106 | - for annotating bitmap graphics: 107 | 108 | ![tikz-annotation](images/bitmaps/readme/tikz-annotations.png) 109 | - for drawing diagrams (this template contains a (basic) `pgf`/`tikz` library for energy systems/thermodynamics/hydraulics/... symbols like pipes, compressors, valves, ...) and 3D sketches. 110 | For a much better and comprehensive collection of TikZ examples, see [here](https://texample.net/tikz/examples/). 111 | 112 | ![tikz-diagram](images/bitmaps/readme/tikz-diagram.png) 113 | ![tikz-libaries](images/bitmaps/readme/tikz-libraries.png) 114 | - back-referencing of citations, using the excellent [`biblatex`](https://ctan.org/pkg/biblatex): 115 | 116 | ![backref](images/bitmaps/readme/backref.png) 117 | - support for elaborate chemical reaction equations, using [`chemmacros`](https://ctan.org/pkg/chemmacros): 118 | 119 | ![chemmacros](images/bitmaps/readme/chem.png) 120 | - comprehensive code syntax highlighting, thanks to [`minted`](https://ctan.org/pkg/minted) and `pygments`: 121 | 122 | ![pygments](images/bitmaps/readme/code.png) 123 | - quick and structural switching of language contexts, provided by [`polyglossia`](https://ctan.org/pkg/polyglossia): 124 | 125 | ![language](images/bitmaps/readme/language.png) 126 | - of course, support for enhanced mathematical typesetting, like highlighted equations or premade macros. 127 | The blue color are *hyperlinks*, turning those symbols into links to the glossary (this can be toggled off). 128 | 129 | ![math](images/bitmaps/readme/math.png) 130 | 131 | ![math-macros](images/bitmaps/readme/math-macros.png) 132 | 133 | [download]: https://github.com/alexpovel/latex-cookbook/releases/latest/download/cookbook.pdf 134 | -------------------------------------------------------------------------------- /bib/README.md: -------------------------------------------------------------------------------- 1 | # **Bib**liographical data 2 | 3 | This directory contains: 4 | 5 | 1. The [bibliography itself](bibliography.bib). 6 | This is auto-generated using [Zotero](https://www.zotero.org/). 7 | Using citation management software (any will do) will help you out greatly in managing larger literature collections. 8 | 1. All sorts of [glossaries](glossaries/), which thanks to [`bib2gls`](https://ctan.org/pkg/bib2gls) now also come in `bib` format. 9 | -------------------------------------------------------------------------------- /bib/bibliography.bib: -------------------------------------------------------------------------------- 1 | 2 | @book{baehrThermodynamikGrundlagenUnd2016, 3 | title = {Thermodynamik: Grundlagen und technische Anwendungen}, 4 | shorttitle = {Thermodynamik}, 5 | author = {Baehr, Hans Dieter and Kabelac, Stephan}, 6 | date = {2016}, 7 | series = {Lehrbuch}, 8 | edition = {16., aktualisierte Auflage}, 9 | publisher = {{Springer Vieweg}}, 10 | location = {{Berlin}}, 11 | isbn = {978-3-662-49568-1}, 12 | langid = {german}, 13 | pagetotal = {671}, 14 | keywords = {Thermodynamics} 15 | } 16 | 17 | @book{birdNaturalLanguageProcessing2009, 18 | title = {Natural Language Processing with {{Python}}}, 19 | author = {Bird, Steven and Klein, Ewan and Loper, Edward}, 20 | date = {2009}, 21 | edition = {1st ed}, 22 | publisher = {{O'Reilly}}, 23 | location = {{Beijing ; Cambridge [Mass.]}}, 24 | abstract = {This is an introduction to natural language processing, which supports a variety of language technologies, from predictive text and email filtering to automatic summarization and translation}, 25 | isbn = {978-0-596-51649-9}, 26 | pagetotal = {479}, 27 | keywords = {Natural language processing (Computer science),Python (Computer program language),Python ,Sprachverarbeitung}, 28 | annotation = {OCLC: ocn301885973} 29 | } 30 | 31 | @book{diracPrinciplesQuantumMechanics1981, 32 | title = {The {{Principles}} of {{Quantum Mechanics}}}, 33 | author = {Dirac, Paul Adrien Maurice}, 34 | date = {1981}, 35 | series = {International Series of Monographs on Physics}, 36 | publisher = {{Clarendon Press}}, 37 | isbn = {978-0-19-852011-5}, 38 | keywords = {physics} 39 | } 40 | 41 | @book{dubbelTaschenbuchFurMaschinenbau2007, 42 | title = {Taschenbuch Für Den {{Maschinenbau}}}, 43 | author = {Dubbel, Heinrich and Grote, Karl-Heinrich and Feldhusen, J.}, 44 | date = {2007}, 45 | edition = {22}, 46 | publisher = {{Springer}}, 47 | location = {{Berlin Heidelberg New York}}, 48 | isbn = {978-3-540-49714-1}, 49 | pagetotal = {1}, 50 | keywords = {Handbooks; manuals; etc,Mechanical engineering} 51 | } 52 | 53 | @article{einsteinZurElektrodynamikBewegter1905, 54 | title = {Zur {{Elektrodynamik}} Bewegter {{Körper}}. ({{German}}) [{{On}} the Electrodynamics of Moving Bodies]}, 55 | author = {Einstein, Albert}, 56 | date = {1905}, 57 | journaltitle = {Annalen der Physik}, 58 | volume = {322}, 59 | number = {10}, 60 | pages = {891--921}, 61 | doi = {http://dx.doi.org/10.1002/andp.19053221004}, 62 | issue = {10} 63 | } 64 | 65 | @book{goossensLaTeXCompanion1993, 66 | title = {The \textbackslash{{LaTeX}}\textbackslash{} {{Companion}}}, 67 | author = {Goossens, Michel and Mittelbach, Frank and Samarin, Alexander}, 68 | date = {1993}, 69 | publisher = {{Addison-Wesley}}, 70 | location = {{Reading, Massachusetts}} 71 | } 72 | 73 | @report{internationalorganizationforstandardizationISO821720172017, 74 | type = {Standard}, 75 | title = {{{ISO}} 8217:2017 - {{Petroleum}} Products - {{Fuels}} (Class {{F}}) - {{Specifications}} of Marine Fuels}, 76 | author = {{International Organization for Standardization}}, 77 | date = {2017-03}, 78 | number = {8217}, 79 | pages = {23}, 80 | institution = {{ISO/TC 28/SC 4}}, 81 | url = {https://www.iso.org/standard/64247.html}, 82 | urldate = {2018-10-08}, 83 | langid = {english} 84 | } 85 | 86 | @mvbook{knuthFundamentalAlgorithms1973, 87 | title = {Fundamental {{Algorithms}}}, 88 | author = {Knuth, Donald E.}, 89 | date = {1973}, 90 | series = {The {{Art}} of {{Computer Programming}}}, 91 | edition = {3}, 92 | volume = {1}, 93 | publisher = {{Addison-Wesley}}, 94 | location = {{Reading, Mass.}}, 95 | isbn = {978-0-201-89683-1}, 96 | langid = {english}, 97 | volumes = {4}, 98 | keywords = {knuth,programming} 99 | } 100 | 101 | @book{knuthTeXbook1986, 102 | title = {The {{TeXbook}}}, 103 | author = {Knuth, Donald Ervin}, 104 | date = {1986}, 105 | series = {Computers \& Typesetting}, 106 | number = {A}, 107 | publisher = {{Addison-Wesley}}, 108 | location = {{Reading, Mass}}, 109 | isbn = {978-0-201-13447-6}, 110 | langid = {english}, 111 | pagetotal = {483}, 112 | keywords = {Computer programs,Computerized typesetting,Mathematics printing,TeX (Computer file)} 113 | } 114 | 115 | @online{mathworksCreateSimpleClass2020, 116 | title = {Create a {{Simple Class}} - {{MATLAB}} \& {{Simulink}}}, 117 | author = {{Mathworks}}, 118 | date = {2020}, 119 | url = {https://www.mathworks.com/help/matlab/matlab_oop/create-a-simple-class.html}, 120 | urldate = {2020-04-14} 121 | } 122 | 123 | @book{mckinneyPythonDataAnalysis2018, 124 | title = {Python for Data Analysis: Data Wrangling with Pandas, {{NumPy}}, and {{IPython}}}, 125 | shorttitle = {Python for Data Analysis}, 126 | author = {McKinney, Wes}, 127 | date = {2018}, 128 | edition = {Second edition}, 129 | publisher = {{O'Reilly Media, Inc}}, 130 | location = {{Sebastopol, California}}, 131 | abstract = {"Get complete instructions for manipulating, processing, cleaning, and crunching datasets in Python. Updated for Python 3.6, the second edition of this hands-on guide is packed with practical case studies that show you how to solve a broad set of data analysis problems effectively. You'll learn the latest versions of pandas, NumPy, IPython, and Jupyter in the process"--Page 4 of cover}, 132 | isbn = {978-1-4919-5766-0}, 133 | pagetotal = {524}, 134 | keywords = {Data mining,Data Mining,Datenanalyse,Datenmanagement,Programming languages (Electronic computers),Python (Computer program language),Python 3.6}, 135 | annotation = {OCLC: ocn959595088} 136 | } 137 | 138 | @book{mollenhauerHandbuchDieselmotoren2007, 139 | title = {Handbuch Dieselmotoren}, 140 | author = {Mollenhauer, Klaus and Tschöke, Helmut}, 141 | date = {2007}, 142 | series = {VDI-Buch}, 143 | edition = {3., neubearb. Aufl}, 144 | publisher = {{Springer}}, 145 | location = {{Berlin}}, 146 | isbn = {978-3-540-72164-2}, 147 | langid = {german}, 148 | pagetotal = {702}, 149 | keywords = {Combustion Engines} 150 | } 151 | 152 | @book{ramalhoFluentPython2015, 153 | title = {Fluent {{Python}}}, 154 | author = {Ramalho, Luciano}, 155 | date = {2015}, 156 | edition = {First edition}, 157 | publisher = {{O'Reilly}}, 158 | location = {{Sebastopol, CA}}, 159 | abstract = {Learn how to write idiomatic, effective Python code by leveraging its best features. Python's simplicity quickly lets you become productive with it, but this often means you aren't using everything the language has to offer. By taking you through Python's key language features and libraries, this practical book shows you how to make your code shorter, faster, and more readable all at the same time--what experts consider Pythonic}, 160 | isbn = {978-1-4919-4600-8}, 161 | pagetotal = {743}, 162 | keywords = {Object-oriented programming languages,Objektorienterad programmering,Programming Languages,Python,Python (Computer program language)}, 163 | annotation = {OCLC: ocn884808025} 164 | } 165 | 166 | @inreference{wikipediacontributorsModelica2021, 167 | title = {Modelica}, 168 | booktitle = {Wikipedia}, 169 | author = {{Wikipedia Contributors}}, 170 | editor = {{Wikipedia Contributors}}, 171 | date = {2021-01-05T18:58:26Z}, 172 | url = {https://en.wikipedia.org/w/index.php?title=Modelica&oldid=998516587}, 173 | urldate = {2021-02-19}, 174 | abstract = {Modelica is an object-oriented, declarative, multi-domain modeling language for component-oriented modeling of complex systems, e.g., systems containing mechanical, electrical, electronic, hydraulic, thermal, control, electric power or process-oriented subcomponents. The free Modelica language is developed by the non-profit Modelica Association. The Modelica Association also develops the free Modelica Standard Library that contains about 1400 generic model components and 1200 functions in various domains, as of version 4.0.0.}, 175 | langid = {english}, 176 | annotation = {Page Version ID: 998516587} 177 | } 178 | 179 | 180 | -------------------------------------------------------------------------------- /bib/glossaries/abbreviations.bib: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | % IT 3 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4 | @abbreviation{uniform_resource_locator, 5 | short={URL}, 6 | long={Uniform Resource Locator}, 7 | } 8 | @abbreviation{single_source_of_truth, 9 | short={SSOT}, 10 | long={Single Source of Truth}, 11 | } 12 | @abbreviation{what_you_see_is_what_you_mean, 13 | short={WYSIWYM}, 14 | long={What You See Is What You Mean}, 15 | } 16 | @abbreviation{portable_document_format, 17 | short={PDF}, 18 | long={Portable Document Format}, 19 | } 20 | @abbreviation{graphical_user_interface, 21 | short={GUI}, 22 | long={Graphical User Interface}, 23 | } 24 | @abbreviation{integrated_development_environment, 25 | short={IDE}, 26 | long={Integrated Development Environment}, 27 | } 28 | @abbreviation{scalable_vector_graphics, 29 | short={SVG}, 30 | long={Scalable Vectors Graphics}, 31 | } 32 | @abbreviation{continuous_integration, 33 | short={CI}, 34 | long={Continuous Integration}, 35 | } 36 | @abbreviation{continuous_delivery, 37 | short={CD}, 38 | long={Continuous Delivery}, 39 | } 40 | @abbreviation{js_object_notation, 41 | short={JSON}, 42 | long={JavaScript Object Notation}, 43 | } 44 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 45 | % Thermodynamics 46 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 47 | @abbreviation{coefficient_of_performance, 48 | short={COP}, 49 | long={Coefficient of Performance}, 50 | } 51 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 52 | % Organizations 53 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 54 | @abbreviation{international_organization_for_standardization, 55 | short={ISO}, 56 | long={International Organization for Standardization}, 57 | } 58 | @abbreviation{int_mar_org, 59 | short={IMO}, 60 | long={International Maritime Organization} 61 | } 62 | @abbreviation{comprehensive_tex_archive_network, 63 | short={CTAN}, 64 | long={Comprehensive \TeX{} Archive Network} 65 | } 66 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 67 | % Marine 68 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 69 | @abbreviation{marine_diesel_oil, 70 | short={MDO}, 71 | long={Marine Diesel Oil} 72 | } 73 | @abbreviation{heavy_fuel_oil, 74 | short={HFO}, 75 | long={Heavy Fuel Oil} 76 | } 77 | -------------------------------------------------------------------------------- /bib/glossaries/constants.bib: -------------------------------------------------------------------------------- 1 | @number{pi, 2 | name={\ensuremath{\pi}}, 3 | description={Pi}, 4 | value={\num{3.14159}\dots{}}, 5 | unit={}, 6 | } 7 | @number{euler, 8 | name={\ensuremath{e}}, 9 | description={Euler's number}, 10 | value={\num{2.71828}\dots{}}, 11 | unit={}, 12 | } 13 | @number{imaginary, 14 | name={\ensuremath{i}}, 15 | description={Imaginary unit}, 16 | value={\(\sqrt{\num{-1}}\)}, 17 | unit={}, 18 | } 19 | -------------------------------------------------------------------------------- /bib/glossaries/index/names.bib: -------------------------------------------------------------------------------- 1 | % Encoding: UTF-8 2 | 3 | In bib files, there are no comment characters (like %). 4 | However, any entry outside the regular (at)type{...} syntax is ignored. 5 | This makes regular text "comments". 6 | Further, bib2gls supports '%' as a comment character. 7 | 8 | File explanation: 9 | the labels cannot contain UTF-8 characters and must stay ASCII. 10 | If such a word occurs, we must provide the name field separately and escape UTF-8. 11 | Provide plural fields just in case they are ever required. 12 | 13 | 14 | % Index entries do not need a 'name' field. 15 | % if the entry label is printable, it can be used. 16 | % An explicit name field is required for escaped characters (umlauts etc.) 17 | 18 | @index{ernst_mach, 19 | name={Mach}, 20 | firstname={Ernst}, 21 | } 22 | @index{edward_tufte, 23 | name={Tufte}, 24 | firstname={Edward}, 25 | } 26 | @index{richard_mollier, 27 | name={Mollier}, 28 | firstname={Richard}, 29 | } 30 | @index{osborne_reynolds, 31 | name={Reynolds}, 32 | firstname={Osborne}, 33 | } 34 | -------------------------------------------------------------------------------- /bib/glossaries/index/terms.bib: -------------------------------------------------------------------------------- 1 | % Encoding: UTF-8 2 | 3 | In bib files, there are no comment characters (%). 4 | However, any entry outside the regular (at)type{...} syntax is ignored. 5 | This makes regular text "comments". 6 | Further, bib2gls supports '%' as a comment character. 7 | 8 | The labels cannot contain UTF-8 characters and must stay ASCII. 9 | If such a word occurs, we must provide the name field separately and escape UTF-8. 10 | Provide plural fields just in case they are ever required. 11 | 12 | @index{latex_package, 13 | name={\LaTeX{} package}, 14 | plural={\LaTeX{} packages}, 15 | } 16 | @index{tikz, 17 | name={Ti\textit{k}Z}, 18 | parent={latex_package}, 19 | } 20 | -------------------------------------------------------------------------------- /bib/glossaries/symbols/greek.bib: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | % Thermodynamics 3 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4 | @symbol{ratio_of_specific_heats, 5 | name={\ensuremath{\kappa}}, 6 | description={Ratio of specific heats}, 7 | unit={\unit{-}}, 8 | } 9 | @symbol{celsius_temperature, 10 | name={\ensuremath{\vartheta}}, 11 | description={(relative) Temperature}, 12 | unit={\unit{\degreeCelsius}}, 13 | } 14 | @symbol{relative_humidity, 15 | name={\ensuremath{\varphi}}, 16 | description={Relative Humidity}, 17 | unit={\unit{\degreeCelsius}}, 18 | } 19 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 20 | % Fluid Mechanics 21 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 22 | @symbol{drag_coefficient, 23 | name={\ensuremath{\zeta}}, 24 | description={Drag Coefficient}, 25 | unit={\unit{-}}, 26 | } 27 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 28 | % Other 29 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 30 | @symbol{mass_fraction, 31 | name={\ensuremath{\gamma}}, 32 | description={Mass fraction}, 33 | unit={\unit{-}}, 34 | } 35 | @symbol{angle_one, 36 | name={\ensuremath{\alpha}}, 37 | description={Angle}, 38 | unit={\unit{\radian}}, 39 | } 40 | -------------------------------------------------------------------------------- /bib/glossaries/symbols/other.bib: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3 | % Math Operators: 4 | % REQUIRED for the built-in macros 5 | % to work (\deriv, \vect etc.)! 6 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 7 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 8 | @entry{derivative, 9 | name={\derivativefmt{\symbolplaceholder}}, 10 | description={infinitesimal change in \symbolplaceholder}, 11 | unit={\symbolplaceholder}, 12 | } 13 | @entry{partial_derivative, 14 | name={\partialderivativefmt{\symbolplaceholder}}, 15 | description={partial, infinitesimal change in \symbolplaceholder}, 16 | unit={\symbolplaceholder}, 17 | } 18 | @entry{difference, 19 | name={\differencefmt{\symbolplaceholder}}, 20 | description={Difference in \symbolplaceholder}, 21 | unit={\symbolplaceholder}, 22 | } 23 | @entry{flow, 24 | name={\flowfmt{\symbolplaceholder}}, 25 | description={\symbolplaceholder{} as a flow quantity}, 26 | unit={\unit{\symbolplaceholder\per\second}}, 27 | } 28 | @entry{nabla, 29 | name={\nablaoperatorfmt{\symbolplaceholder}}, 30 | description={Vector of partial derivatives (Nabla operator) of \symbolplaceholder}, 31 | unit={\unit{-}}, 32 | } 33 | @entry{mean, 34 | name={\meanfmt{\symbolplaceholder}}, 35 | description={Arithmetic mean of \symbolplaceholder{}}, 36 | unit={\symbolplaceholder}, 37 | } 38 | @entry{logmean, 39 | name={\logmeanfmt{\symbolplaceholder}}, 40 | description={Logarithmic mean of \symbolplaceholder{}}, 41 | unit={\symbolplaceholder}, 42 | } 43 | @entry{vector, 44 | name={\ensuremath{\vectfmt{x}}}, 45 | description={Vector}, 46 | unit={\unit{-}}, 47 | } 48 | @entry{abs, 49 | name={\ensuremath{\absfmt*{\symbolplaceholder}}}, 50 | description={Absolute of \symbolplaceholder}, 51 | unit={\symbolplaceholder}, 52 | } 53 | -------------------------------------------------------------------------------- /bib/glossaries/symbols/roman.bib: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | % Thermodynamic state 3 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4 | @symbol{pressure, 5 | name={\ensuremath{p}}, 6 | description={Pressure}, 7 | unit={\unit{\pascal}}, 8 | } 9 | @symbol{abs_temperature, 10 | name={\ensuremath{T}}, 11 | description={(absolute) Temperature}, 12 | unit={\unit{\kelvin}}, 13 | } 14 | @symbol{volume, 15 | name={\ensuremath{V}}, 16 | specific={\ensuremath{v}}, 17 | description={Volume}, 18 | unit={\unit{\meter\cubed}}, 19 | } 20 | @symbol{gas_constant, 21 | name={\ensuremath{R}}, 22 | specific={\ensuremath{R}}, 23 | description={(specific) Gas Constant}, 24 | unit={\unit{\joule\per\kilogram\per\kelvin}}, 25 | } 26 | @symbol{mass, 27 | name={\ensuremath{m}}, 28 | description={Mass}, 29 | unit={\unit{\kilogram}}, 30 | } 31 | @symbol{density, 32 | name={\ensuremath{\rho}}, 33 | description={Density}, 34 | unit={\unit{\kilogram\per\meter\cubed}}, 35 | } 36 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 37 | % Thermodynamic change of state / energy 38 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 39 | @symbol{enthalpy, 40 | name={\ensuremath{H}}, 41 | specific={\ensuremath{h}}, 42 | description={Enthalpy}, 43 | unit={\unit{\joule}}, 44 | } 45 | @symbol{velocity, 46 | name={\ensuremath{c}}, 47 | description={Velocity/Speed}, 48 | unit={\unit{\meter\per\second}}, 49 | } 50 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 51 | % Air conditioning 52 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 53 | @symbol{moisture_content, 54 | name={\ensuremath{x}}, 55 | description={Moisture Content}, 56 | unit={% 57 | \unit{ 58 | \gram_{\glsfmtname{sub.water}} 59 | \per 60 | \kilogram_{\glsfmtname{sub.dry}\glsfmtname{sub.air}} 61 | } 62 | }, 63 | } 64 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 65 | % Material properties 66 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 67 | @symbol{heating_value, 68 | name={\ensuremath{H_{\glsentryname{sub.inferior}}}}, 69 | specific={\ensuremath{H_{\glsentryname{sub.inferior}}}}, 70 | description={(specific) Heating Value}, 71 | unit={\unit{\joule\per\kilogram}}, 72 | } 73 | @symbol{heat_capacity, 74 | name={\ensuremath{C}}, 75 | specific={\ensuremath{c}}, 76 | description={Heat capacity}, 77 | unit={\unit{\joule\per\kelvin}}, 78 | } 79 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 80 | % Coordinates etc. 81 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 82 | % REQUIRED for built-in \posderiv to work: 83 | @symbol{first_cart_coord, 84 | name={\ensuremath{x}}, 85 | description={First Cartesian coordinate (length)}, 86 | unit={\unit{\meter}}, 87 | } 88 | @symbol{second_cart_coord, 89 | name={\ensuremath{y}}, 90 | description={Second Cartesian coordinate (width)}, 91 | unit={\unit{\meter}}, 92 | } 93 | @symbol{third_cart_coord, 94 | name={\ensuremath{z}}, 95 | description={Third Cartesian coordinate (height)}, 96 | unit={\unit{\meter}}, 97 | } 98 | @symbol{radius, 99 | name={\ensuremath{r}}, 100 | description={Radius}, 101 | unit={\unit{\meter}}, 102 | } 103 | @symbol{area, 104 | name={\ensuremath{A}}, 105 | description={Area}, 106 | unit={\unit{\meter\squared}}, 107 | } 108 | % REQUIRED for built-in \timederiv to work: 109 | @symbol{time, 110 | name={\ensuremath{t}}, 111 | description={Time}, 112 | unit={\unit{\second}}, 113 | } 114 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 115 | % Electrical 116 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 117 | @symbol{voltage, 118 | name={\ensuremath{U_{\glsentryname{sub.electric}}}}, 119 | description={Voltage}, 120 | unit={\unit{\volt}}, 121 | } 122 | @symbol{electric_current, 123 | name={\ensuremath{J_{\glsentryname{sub.electric}}}}, 124 | description={Electric current}, 125 | unit={\unit{\ampere}}, 126 | } 127 | @symbol{electrical_resistance, 128 | name={\ensuremath{R_{\glsentryname{sub.electric}}}}, 129 | description={Electrical resistance}, 130 | unit={\unit{\ohm}}, 131 | } 132 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 133 | % Dimensionless Quantities 134 | % Use \operatorname (for which \DeclareMathOperator is a wrapper) 135 | % for correct spacing etc. 136 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 137 | @symbol{mach_number, 138 | name={\ensuremath{\operatorname{M}}}, 139 | description={\glsfmtname{name.ernst_mach} number}, 140 | unit={\unit{-}}, 141 | } 142 | @symbol{reynolds_number, 143 | name={\ensuremath{\operatorname{Re}}}, 144 | description={\glsfmtname{name.osborne_reynolds} number}, 145 | unit={\unit{-}}, 146 | } 147 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 148 | % Other 149 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 150 | @symbol{component, 151 | name={\ensuremath{n}}, 152 | description={Component}, 153 | unit={\unit{-}}, 154 | } 155 | @symbol{count, 156 | name={\ensuremath{k}}, 157 | description={Count/Quantity}, 158 | unit={\unit{-}}, 159 | } 160 | -------------------------------------------------------------------------------- /bib/glossaries/symbols/subscripts.bib: -------------------------------------------------------------------------------- 1 | @symbol{inferior, 2 | name={\text{i}}, 3 | description={inferior}, 4 | } 5 | @symbol{water, 6 | name={\text{w}}, 7 | description={Water}, 8 | } 9 | @symbol{dry, 10 | name={\text{d}}, 11 | description={dry}, 12 | } 13 | @symbol{air, 14 | name={\text{a.}}, 15 | description={air}, 16 | } 17 | @symbol{electric, 18 | name={\text{el.}}, 19 | description={electric}, 20 | } 21 | @symbol{thermal, 22 | name={\text{th}}, 23 | description={thermal}, 24 | } 25 | -------------------------------------------------------------------------------- /chapters/README.md: -------------------------------------------------------------------------------- 1 | # Content files 2 | 3 | This directory contains all the source `tex` files with the document content. 4 | Splitting up files, putting them here and then running `\import` or `\subimport` on them is a good way of modularisation. 5 | It allows to compile only what is needed by commenting out unneeded `\(sub)import` statements, greatly speeding up compilation times. 6 | -------------------------------------------------------------------------------- /chapters/frontmatter.tex: -------------------------------------------------------------------------------- 1 | % Helper file that pulls subchapters together. 2 | 3 | % Set initial pages to alpha, so that they do not collide with later Arabic numbering 4 | % in the generated PDF. This won't show in print because page numbers aren't displayed 5 | % until later. But you will be able to print the title page by printing page 'a', which 6 | % would otherwise overlap with page '1', aka the first actual text page. 7 | \pagenumbering{alph} 8 | \maketitle% Print main title page 9 | \subimport{frontmatter/}{colophon} 10 | 11 | \frontmatter% In KOMAScript, resets pagenumber, uses Roman numerals etc. 12 | 13 | % Note that \subincludefrom{}{} cannot be nested, therefore us \subimport 14 | \subimport{frontmatter/}{task} 15 | \subimport{frontmatter/}{authorship_declaration} 16 | \subimport{frontmatter/}{abstract} 17 | 18 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 19 | % Lists of Content 20 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 21 | 22 | \tableofcontents 23 | 24 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 25 | % addchap is KOMA equivalent for \chapter*, but also creates ToC entry, see also 26 | % https://tex.stackexchange.com/a/116085/120853 27 | % Use built-in macro \glossaryname for proper internationalization. With polyglossia, it 28 | % will contain \text{}, which has been taken care of 29 | % using \pdfstringdefDisableCommands{} in the class file 30 | \addchap{\glossaryname}% 31 | \label{ch:glossary} 32 | 33 | \emph{% 34 | \TransGlossaryLegend{}% 35 | }% 36 | 37 | % Print "unsorted" glossaries; these are in fact sorted, but externally using bib2gls. 38 | % These will throw 'Token not allowed in PDF, removing \text' warning. 39 | % Specify title= manually if that gets too annoying. 40 | \printunsrtglossary[ 41 | type=symbols, 42 | style=symbunitlong, 43 | ] 44 | \printunsrtglossary[ 45 | type=numbers, 46 | style=numberlong, 47 | ] 48 | \printunsrtglossary[ 49 | type=subscripts, 50 | style=mcolalttree, 51 | nonumberlist, 52 | ] 53 | \printunsrtglossary[ 54 | type=abbreviations, 55 | style=long3colheader, 56 | title=\TransAcronyms{}, 57 | ] 58 | 59 | \addchap{\glossaryname{} without page lists}% 60 | 61 | \emph{ 62 | The following styles do not contain page lists of the entries' occurrences, 63 | leading to a cleaner, more concise look. 64 | Refer to the source code on how to achieve this (which options and styles to use). 65 | } 66 | 67 | % For all sorts of styles, see also 68 | % https://www.dickimaw-books.com/gallery/glossaries-styles/ 69 | 70 | % Simply pass the `nonumberlist` parameter where desired/required: 71 | \printunsrtglossary[ 72 | type=symbols, 73 | style=symbunitlong, 74 | nonumberlist, 75 | ] 76 | \printunsrtglossary[ 77 | type=numbers, 78 | style=numberlong, 79 | nonumberlist, 80 | ] 81 | \printunsrtglossary[ 82 | type=subscripts, 83 | style=mcolalttree, 84 | nonumberlist, 85 | ] 86 | \printunsrtglossary[ 87 | type=abbreviations, 88 | % If `nonumberlist` is passed, the `long3colheader` style simply leaves the 89 | % corresponding table cells *empty* (leading to an entirely empty column), but does 90 | % not actually remove the column. So use a different, but equivalent style 91 | % altogether: 92 | style=longheader, 93 | % The `longheader` style prints the page list behind the description, just not in a 94 | % separate column. So also explicitly suppress the generation of that: 95 | nonumberlist, 96 | title=\TransAcronyms{}, 97 | ] 98 | 99 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 100 | \listoffigures% 101 | 102 | \listoftables% 103 | 104 | \listofexamples% 105 | 106 | \listoflistings% 107 | 108 | \listofreactions% 109 | 110 | \subimport{frontmatter/}{preface} 111 | -------------------------------------------------------------------------------- /chapters/frontmatter/abstract.tex: -------------------------------------------------------------------------------- 1 | % Use built-in macro for internationalization 2 | \chapter*{\abstractname} 3 | 4 | \Blindtext 5 | 6 | \begin{itemize} 7 | \item We found this out, 8 | \item and also that! 9 | \end{itemize} 10 | -------------------------------------------------------------------------------- /chapters/frontmatter/authorship_declaration.tex: -------------------------------------------------------------------------------- 1 | % Put page onto its own _recto_ page. It is a page intended to be signed and stamped. 2 | % Therefore, it cannot be verso, since then there is no paper behind this page to 3 | % support writing on it. 4 | \cleardoubleoddpage 5 | 6 | \vspace*{\fill} 7 | 8 | \subsection*{\TransAuthorshipDeclTitle{}} 9 | 10 | \TransAuthorshipDeclText{} 11 | 12 | \signaturefield{} 13 | -------------------------------------------------------------------------------- /chapters/frontmatter/colophon.tex: -------------------------------------------------------------------------------- 1 | % No \cleardoubleoddpage shenanigans: the colophon page is supposed to be on the verso 2 | % behind the title. 3 | 4 | \thispagestyle{empty} 5 | \vspace*{\fill} 6 | 7 | \begingroup% Keep changes local to this group 8 | \hypersetup{hidelinks} 9 | \color{g2} 10 | \footnotesize 11 | 12 | \begin{tabular}{ 13 | r 14 | l 15 | } 16 | % \TransXYZ commands are from translations file 17 | Name & 18 | \texttt{\textbf{% 19 | \jobname{}% Always print the job name 20 | }} 21 | \makeatletter 22 | % Only print if censoring is on; command defined by kvoptions 23 | \ifacp@censoring% 24 | % This duplicate \textt\textbf is necessary. 25 | % This if construct cannot be inside the one font commands 26 | % for \jobname{} 27 | \texttt{\textbf{(\TransCensorNotice{})}} 28 | \fi 29 | \makeatother 30 | \\ 31 | \TransCompiledOn{} & \textbf{\DTMnow{}}\\ 32 | \addlinespace 33 | \faIcon{git-alt} & \texttt{\textbf{\GitShortSHA{}} (\GitRefName{})} \\ 34 | \addlinespace 35 | Engine & \prettybanner{}\\ 36 | \LaTeX{} Version & \hologo{\fmtname} (\fmtversion)\\ 37 | \glossaryname{} & \texttt{glossaries-extra} + \texttt{bib2gls}\\ 38 | \bibname{} & biblatex + \hologo{biber}\\ 39 | \TransGenerator{} & \texttt{latexmk}\\ 40 | \TransLatexClass{} & \KOMAScriptVersion{} 41 | \end{tabular}% 42 | \endgroup% 43 | -------------------------------------------------------------------------------- /chapters/frontmatter/preface.tex: -------------------------------------------------------------------------------- 1 | \addchap{Preface} 2 | 3 | This document is not a beginner guide. 4 | There is a wide choice of those out there already, both free and paid for. 5 | However, what is lacking is a collection of modern, or even at least current, 6 | best practices. 7 | If you scouted through package documentations and 8 | \href{https://tex.stackexchange.com/}{StackExchange} 9 | long enough, you would eventually get an idea of what is current, idiomatic \LaTeX{} 10 | and what is not. 11 | This is how I learned \LaTeX{} too, so I cannot recommend any useful beginner books. 12 | You might want to check out \href{https://www.overleaf.com/}{Overleaf} though, 13 | an online \LaTeX{} editor% 14 | \footnote{% 15 | I do not recommend using online editors. 16 | You are putting your hard work onto some remote, foreign server, relying on 17 | their ongoing availability and forfeiting the chance of understanding \LaTeX{}, 18 | in case you have to continue locally. 19 | Theses containing confidential material should also not be hosted externally. 20 | } 21 | with a large knowledge database. 22 | 23 | This document is an attempt at collecting best practices 24 | --- or at least, useful approaches --- 25 | and pointing out the old ones they could, often should, and sometimes absolutely have to replace. 26 | See also \href{https://web.archive.org/web/20210317090850/https://user.math.uni-bremen.de/~grimpen/LaTeX.html}{here} for a second opinion on the topic. 27 | More than most other languages, the \LaTeX{} code in circulation world\-/wide is 28 | quite aged. 29 | While that code does not necessarily get \emph{worse}, it also does not exactly 30 | age like cheese and wine would. 31 | To that end, notice how the packages integral to this document are actively 32 | maintained and kept modern. 33 | 34 | \paragraph{Usage as a Cookbook} 35 | This document is supposed to be used in a \emph{cookbook} style. 36 | That is, it is not meant to be read cover to cover 37 | (declaring it a cookbook is also a useful excuse for the mess I made). 38 | 39 | The document contains various \enquote{recipes}, most of which exist in parallel and 40 | are independent of one another. 41 | The goal is to answer questions of the form \emph{How can this and that be done?} 42 | A quick search in the (printed) output or the source code is supposed to deliver 43 | answers. 44 | 45 | \paragraph{Usage as a Template} 46 | Considerable effort went into the class file, aka the template. 47 | It pulls all settings together, producing an output that is very different from 48 | vanilla \LaTeX{}. 49 | Therefore, feel free to rip out all the cookbook content, keeping just the settings 50 | files to be used as a template. 51 | 52 | \paragraph{Source Code} 53 | This document is meant to be read side\-/by\-/side with its source code. 54 | That is why there is almost no source code in the printed output itself. 55 | If you are curious how a certain output is achieved, navigate to the source code 56 | itself. 57 | This approach was chosen since, plainly, code does not lie, while annotations and 58 | comments might. 59 | So while the printed output will always remain true to its actual source code, 60 | duplicating that source code so it can be read in the printed output directly 61 | is just another vector for errors to creep in. 62 | 63 | \paragraph{Source Repository} 64 | The source repository for this document is at 65 | \begin{center} 66 | \url{https://github.com/alexpovel/latex-cookbook} . 67 | \end{center} 68 | Any references to the \enquote{source} or \enquote{repository} refer to that project. 69 | -------------------------------------------------------------------------------- /chapters/frontmatter/task.tex: -------------------------------------------------------------------------------- 1 | \chapter*{\TransTask{}} 2 | 3 | \makeatletter 4 | \begin{tabular}{ 5 | l 6 | p{0.7\linewidth} 7 | } 8 | \TransFor{}: & \textbf{\@author{}} [\@idnumber{}]\\ 9 | \TransTopic{}: & \textbf{\@title} (\@documenttype{}) 10 | \end{tabular}\\[\baselineskip] 11 | \makeatother 12 | 13 | \blindtext 14 | 15 | \begin{itemize} 16 | \item First you are doing this, 17 | \item then another thing, 18 | \item lastly that. 19 | \end{itemize} 20 | 21 | You will be working on this a lot. 22 | 23 | \signaturefield{} 24 | -------------------------------------------------------------------------------- /chapters/mainmatter.tex: -------------------------------------------------------------------------------- 1 | \mainmatter 2 | 3 | % Uncomment the following if you'd like vertical space (with no indentation) between 4 | % paragraphs, instead of the default of *no* vertical space *with* indentation. 5 | % This lives inside the main matter since for example the `mcolalttree` style for 6 | % `glossaries-extra` (glossaries live in the front matter) is based around `\par`, which 7 | % breaks if we request the `parskip` option. 8 | 9 | % \KOMAoptions{parskip} 10 | 11 | \subimport{mainmatter/}{usage} 12 | \subimport{mainmatter/}{base-features} 13 | \subimport{mainmatter/}{floats} 14 | \subimport{mainmatter/}{code-listings} 15 | -------------------------------------------------------------------------------- /cookbook.tex: -------------------------------------------------------------------------------- 1 | % Magic Comment: this template requires LuaLaTeX. The following 'magic comment' is 2 | % recognized by editors and will ensure lualatex engine use: 3 | 4 | %!TEX TS-program = lualatex 5 | 6 | % Note that package `svg` also requires elevation, aka the `--shell-escape` option to 7 | % read/write SVG/PDF files. 8 | 9 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10 | 11 | \documentclass[% 12 | % Global language, passed down to packages and base class. 13 | language=english, 14 | titlestyle=thesis,% Style of titlepage: thesis, book or uncomment for vanilla 15 | BCOR=5mm,% Binding Correction. Cannot be known a priori, only guesstimated 16 | a4,% Options: a4/a5 for a4 paper with 11pt or a5 paper with 10pt, respectively 17 | % Toggle all \censor{} etc. commands, e.g. to generate a public version: 18 | censoring=true, 19 | ]{acp}% Load custom class file (*.cls) 20 | 21 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 22 | 23 | % This is still the preamble. You can insert '\newcommand's and all other stuff here. If 24 | % it is a more long-term change, write it to the class (*.cls) file. You also find all 25 | % settings to existing packages there. 26 | 27 | %\usepackage{showframe}% Uncomment for debugging (show frames) 28 | 29 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 30 | 31 | % The following occurs here so VSCode's 'LaTeX Workshop' extension can find all bib 32 | % resources (it doesn't seem to look into class files): 33 | \addbibresource{bib/bibliography.bib}% *.bib file goes here 34 | 35 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 36 | % Titlepage and document metadata content: 37 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 38 | 39 | \author{Alex Povel}% 40 | 41 | \date{\DTMtoday{}}% Print today's date w/ syntax of newer package datetime2 42 | 43 | \title{A modern \LaTeX{} cookbook} 44 | 45 | \subtitle{% Examiners or other, rather arbitrary content 46 | \begin{tabular}[t]{% [t] sets tabular anchor to the top 47 | @{}% Remove horizontal space left of tabular 48 | l% If no really good reason to do otherwise, always left-align cell 49 | @{\ }% '\ ' (backslash-space) is a small space, here a column separator 50 | l 51 | l 52 | @{}% Remove horizontal space right of tabular 53 | } 54 | \nth{1} & Examiner & Prof.\ Jane Doe\\ 55 | \nth{2} & Examiner & Prof.\ Foo Bar\\ 56 | \multicolumn{2}{@{}l}{Supervisor} & John Doe, M.Sc.% 57 | \end{tabular} 58 | }% 59 | 60 | \documenttype{Example Document}% Document type, like Master Thesis, PhD Thesis, ... 61 | 62 | \idnumber{666}% Enrolment/student ID number if applicable 63 | 64 | \publishers{% 65 | University of Greatness\\% 66 | Institute of Big Bang% 67 | }% Institutions, university, etc. Can also use graphics here 68 | 69 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 70 | 71 | \begin{document} 72 | \import{chapters/}{frontmatter} 73 | \import{chapters/}{mainmatter} 74 | \import{chapters/}{backmatter} 75 | \end{document} 76 | -------------------------------------------------------------------------------- /data/README.md: -------------------------------------------------------------------------------- 1 | # (Raw) data 2 | 3 | This directory contains data used inside the main document, e.g. CSV data for `pgfplots`. 4 | You can put all sorts of things here. 5 | -------------------------------------------------------------------------------- /data/diffuser.csv: -------------------------------------------------------------------------------- 1 | R,M,Pi,Theta,Rho,alpha,R_pres 2 | 1,0.8,1,1,1,15,1 3 | 1.016666667,0.783683071,1.015164946,1.004602799,1.010513754,14.86740098,1.016666667 4 | 1.033333333,0.768036211,1.029662489,1.008966272,1.020512299,14.74464478,1.033333333 5 | 1.05,0.753014821,1.043529062,1.013107287,1.030028187,14.63084233,1.05 6 | 1.066666667,0.738578426,1.056798955,1.017041194,1.039091593,14.52520715,1.066666667 7 | 1.083333333,0.724690667,1.069503564,1.020781859,1.047729791,14.42704236,1.083333333 8 | 1.1,0.711318399,1.081672288,1.024341949,1.055967969,14.33572754,1.1 9 | 1.116666667,0.698431125,1.093333083,1.027733116,1.063829768,14.25070752,1.116666667 10 | 1.133333333,0.686000827,1.104512334,1.030966065,1.071337236,14.17148429,1.133333333 11 | 1.15,0.674001977,1.115234408,1.034050577,1.078510503,14.09761064,1.15 12 | 1.166666667,0.662411065,1.125522178,1.036995663,1.08536826,14.02868356,1.166666667 13 | 1.183333333,0.651206258,1.135397416,1.039809668,1.09192812,13.96433827,1.183333333 14 | 1.2,0.64036732,1.144880709,1.042500316,1.098206582,13.90424402,1.2 15 | 1.216666667,0.62987562,1.153991176,1.045074722,1.104218819,13.84810071,1.216666667 16 | 1.233333333,0.619713857,1.162746803,1.047539484,1.109978975,13.79563529,1.233333333 17 | 1.25,0.609865858,1.171164727,1.049900747,1.115500423,13.74659837,1.25 18 | 1.266666667,0.600316526,1.179261177,1.052164226,1.120795735,13.70076187,1.266666667 19 | 1.283333333,0.591051844,1.187051288,1.054335225,1.125876533,13.65791712,1.283333333 20 | 1.3,0.58205872,1.194549326,1.056418685,1.13075369,13.61787279,1.3 21 | 1.316666667,0.573324841,1.201768898,1.058419229,1.135437514,13.58045281,1.316666667 22 | 1.333333333,0.56483865,1.208722909,1.060341177,1.139937725,13.54549501,1.333333333 23 | 1.35,0.55658935,1.215423436,1.062188559,1.144263347,13.51285004,1.35 24 | 1.366666667,0.5485668,1.221881881,1.063965144,1.148422848,13.48238004,1.366666667 25 | 1.383333333,0.540761419,1.228109134,1.065674473,1.152424276,13.45395735,1.383333333 26 | 1.4,0.533164175,1.234115536,1.067319869,1.156275239,13.42746374,1.4 27 | 1.416666667,0.525766583,1.239910796,1.068904442,1.159982826,13.40278965,1.416666667 28 | 1.433333333,0.518560637,1.245504093,1.070431116,1.163553708,13.37983341,1.433333333 29 | 1.45,0.511538748,1.250904206,1.071902642,1.166994238,13.35850038,1.45 30 | 1.466666667,0.50469373,1.256119485,1.073321614,1.170310436,13.33870246,1.466666667 31 | 1.483333333,0.498018804,1.261157785,1.074690467,1.17350793,13.32035762,1.483333333 32 | 1.5,0.49150755,1.266026551,1.076011499,1.176592027,13.30338937,1.5 33 | 1.516666667,0.485153862,1.270732905,1.077286878,1.179567794,13.28772618,1.516666667 34 | 1.533333333,0.478951937,1.275283637,1.078518652,1.182440039,13.27330119,1.533333333 35 | 1.55,0.472896282,1.279685147,1.079708753,1.185213275,13.26005186,1.55 36 | 1.566666667,0.466981677,1.283943509,1.080859007,1.18789176,13.24791965,1.566666667 37 | 1.583333333,0.461203143,1.288064544,1.081971143,1.190479573,13.2368496,1.583333333 38 | 1.6,0.455555936,1.292053806,1.083046797,1.192980589,13.22679012,1.6 39 | 1.616666667,0.450035549,1.295916543,1.084087518,1.195398454,13.21769282, 40 | 1.633333333,0.444637686,1.299657743,1.085094773,1.197736618,13.20951217, 41 | 1.65,0.439358241,1.303282192,1.086069953,1.199998387,13.20220536, 42 | 1.666666667,0.434193291,1.306794463,1.087014381,1.202186913,13.195732, 43 | -------------------------------------------------------------------------------- /data/matlab2tikz_table_example.tex: -------------------------------------------------------------------------------- 1 | % This file was created by matlab2tikz. 2 | % 3 | %The latest updates can be retrieved from 4 | % http://www.mathworks.com/matlabcentral/fileexchange/22022-matlab2tikz-matlab2tikz 5 | %where you can also make suggestions and rate matlab2tikz. 6 | % 7 | \begin{tikzpicture} 8 | 9 | \begin{axis}[% 10 | % width=6.053in, 11 | % height=5.538in, 12 | % at={(1.338in,1.274in)}, 13 | scale only axis, 14 | xmin=0, 15 | xmax=150000, 16 | xlabel style={font=\color{white!15!black}}, 17 | xlabel={Reynold's Number [-]}, 18 | ymin=-20, 19 | ymax=60, 20 | ylabel style={font=\color{white!15!black}}, 21 | ylabel={Drag coefficient $\zeta$ [-]}, 22 | axis background/.style={fill=white}, 23 | axis x line*=bottom, 24 | axis y line*=left, 25 | xmajorgrids, 26 | ymajorgrids, 27 | legend style={legend cell align=left, align=left, draw=white!15!black}, 28 | table/col sep=space, 29 | ] 30 | \addplot [color=black, only marks, mark=o, mark options={solid, black}] 31 | plot [error bars/.cd, y dir=both, y explicit, error bar style={line width=0.5pt}, error mark options={line width=0.5pt, mark size=6.0pt, rotate=90}] 32 | table[row sep=crcr, y error plus index=2, y error minus index=3]{% 33 | 91450.4005348642 18.8206494302446 0.22784420833039 0.22784420833039\\ 34 | 9600.2287009917 17.0940855567971 18.8769483727188 18.8769483727188\\ 35 | 98040.7874556726 18.6728583096816 0.202036909770865 0.202036909770865\\ 36 | 65157.2349669312 19.3095953696594 0.418204806276939 0.418204806276939\\ 37 | 49337.9741089259 19.8795961310237 0.722764642682136 0.722764642682136\\ 38 | 16355.6858822063 21.6588058718839 6.48504129977849 6.48504129977849\\ 39 | 68662.1156767816 19.2826158073702 0.379906394244728 0.379906394244728\\ 40 | 88193.8884388812 18.8512612583498 0.241587510229639 0.241587510229639\\ 41 | 52897.2052503459 19.7556610691345 0.63682805169426 0.63682805169426\\ 42 | 45361.2310463829 19.9283864286216 0.857322986465614 0.857322986465614\\ 43 | 35629.1264772871 20.5353610928944 1.37414627818398 1.37414627818398\\ 44 | 95043.2938482082 18.7591297797428 0.213416328531058 0.213416328531058\\ 45 | 61640.0699375336 19.465583058119 0.466703246588861 0.466703246588861\\ 46 | 58751.4523099524 19.4914842217088 0.508777380354382 0.508777380354382\\ 47 | 41886.8624922781 20.2213805881069 0.988945957346638 0.988945957346638\\ 48 | 71787.1923690876 19.183171510498 0.349958881481435 0.349958881481435\\ 49 | 55566.6189222481 19.6884300185046 0.57492765151384 0.57492765151384\\ 50 | 22414.4905749956 21.4563894028588 3.46477796770842 3.46477796770842\\ 51 | 29891.5116045859 20.8072061681644 1.95317002720734 1.95317002720734\\ 52 | 81648.5561586976 18.9338775855205 0.276308105964505 0.276308105964505\\ 53 | 84915.3205825358 18.9018965006065 0.25775055811768 0.25775055811768\\ 54 | 12748.6992906755 20.956252098279 10.6964468685791 10.6964468685791\\ 55 | 19702.7655801537 21.3720690437585 4.47489311485873 4.47489311485873\\ 56 | 78363.5688516276 19.0751370068433 0.297546198952902 0.297546198952902\\ 57 | 32704.8269868436 20.8291059476584 1.63441062956786 1.63441062956786\\ 58 | 39454.0447791576 20.3956969160794 1.11850790152941 1.11850790152941\\ 59 | 25852.5857440217 21.5131319639883 2.60715319679087 2.60715319679087\\ 60 | 75047.302268985 19.1129078534408 0.322186799342343 0.322186799342343\\ 61 | }; 62 | \addlegendentry{9 bar, 30 $^\circ$C} 63 | 64 | \addplot [color=blue, only marks, mark=o, mark options={solid, blue}] 65 | plot [error bars/.cd, y dir=both, y explicit, error bar style={line width=0.5pt}, error mark options={line width=0.5pt, mark size=6.0pt, rotate=90}] 66 | table[row sep=crcr, y error plus index=2, y error minus index=3]{% 67 | 90364.8194858743 18.851972315629 0.305217342375055 0.305217342375055\\ 68 | 8076.2640578434 24.0111558434839 35.8029501848227 35.8029501848227\\ 69 | 50772.0591562781 19.7992917932574 0.928394801097195 0.928394801097195\\ 70 | 66195.4322434412 19.2914810641625 0.550235869227531 0.550235869227531\\ 71 | 47363.6661097263 20.0685366715685 1.0630574120011 1.0630574120011\\ 72 | 19902.7764508919 21.2759580135189 5.98521694141482 5.98521694141482\\ 73 | 39900.5151261104 20.5397185970455 1.48849529409474 1.48849529409474\\ 74 | 74866.732832787 19.0900594677447 0.434436734327329 0.434436734327329\\ 75 | 82545.9819399738 18.9439559950128 0.361002096005894 0.361002096005894\\ 76 | 106171.719883028 18.6283535384433 0.229496342278619 0.229496342278619\\ 77 | 94122.014260214 18.7599655960001 0.282619972807026 0.282619972807026\\ 78 | 55431.0307804117 19.61223734667 0.783444980800781 0.783444980800781\\ 79 | 59322.7541290298 19.6319108649163 0.684931628377185 0.684931628377185\\ 80 | 114221.038645558 18.4694576373584 0.203347977101083 0.203347977101083\\ 81 | 78925.5166005358 19.0282740070502 0.393135093952 0.393135093952\\ 82 | 63096.2993854333 19.3936301169532 0.605948000756784 0.605948000756784\\ 83 | 86358.0944477848 18.8993234493532 0.331341638288088 0.331341638288088\\ 84 | 110454.377590452 18.567036984956 0.214660611248231 0.214660611248231\\ 85 | 35864.0452240558 20.7795087552391 1.84052287954811 1.84052287954811\\ 86 | 102270.885599624 18.6534024509903 0.244662856478561 0.244662856478561\\ 87 | 15625.3491197509 23.0212986293325 9.68121139016299 9.68121139016299\\ 88 | 98275.2673711873 18.6797685109276 0.262281703155193 0.262281703155193\\ 89 | 31352.5742431042 21.0124223239215 2.41763424066977 2.41763424066977\\ 90 | 12313.9582502865 22.5336653922509 15.5170405633573 15.5170405633573\\ 91 | 118521.184105338 18.4634946805162 0.191715543444072 0.191715543444072\\ 92 | 27954.591413931 21.1733665963443 3.03909219686198 3.03909219686198\\ 93 | 23661.526874057 21.8398598857805 4.23960949267591 4.23960949267591\\ 94 | 70936.4289641694 19.2203716274935 0.481640104330054 0.481640104330054\\ 95 | 43616.6098039867 20.3724031756756 1.24623498410928 1.24623498410928\\ 96 | }; 97 | \addlegendentry{13.2 bar, 45 $^\circ$C} 98 | 99 | \addplot [color=red, only marks, mark=o, mark options={solid, red}] 100 | plot [error bars/.cd, y dir=both, y explicit, error bar style={line width=0.5pt}, error mark options={line width=0.5pt, mark size=6.0pt, rotate=90}] 101 | table[row sep=crcr, y error plus index=2, y error minus index=3]{% 102 | 17867.5515609687 21.7652508894877 9.15368581910848 9.15368581910848\\ 103 | 125637.055996345 18.3877470989716 0.20747930927834 0.20747930927834\\ 104 | 49304.731241175 19.807149989706 1.22247182825836 1.22247182825836\\ 105 | 107667.483438579 18.6074812032667 0.27078355428531 0.27078355428531\\ 106 | 13536.3513622991 22.9216117473262 16.0120267998002 16.0120267998002\\ 107 | 71994.5089139876 19.1461599074966 0.579982264504498 0.579982264504498\\ 108 | 58949.4992802703 19.4584247735011 0.863655495599455 0.863655495599455\\ 109 | 22441.0358182932 20.9345419939241 5.80047673858736 5.80047673858736\\ 110 | 44296.5080074942 19.8307916472566 1.50683347198268 1.50683347198268\\ 111 | 36163.6188854124 20.1076548679491 2.265078120627 2.265078120627\\ 112 | 121252.135326159 18.4363699283627 0.220566362796363 0.220566362796363\\ 113 | 85072.0354168332 18.8324850607434 0.418963400171204 0.418963400171204\\ 114 | 103030.125538593 18.6109968334098 0.292673058569925 0.292673058569925\\ 115 | 62664.4453756571 19.3182930613143 0.76166308494462 0.76166308494462\\ 116 | 66814.802347003 19.1511266386389 0.671621933741905 0.671621933741905\\ 117 | 40023.6860323227 20.3563108994464 1.84868057936682 1.84868057936682\\ 118 | 98428.0786967929 18.7052786521598 0.318212576297495 0.318212576297495\\ 119 | 94101.3387888276 18.7365240146046 0.345945890970535 0.345945890970535\\ 120 | 112249.405136342 18.541593643746 0.2517944419942 0.2517944419942\\ 121 | 31272.4427821611 20.5767680935139 3.01988954371356 3.01988954371356\\ 122 | 76452.8638484087 19.0625190030148 0.518185514149112 0.518185514149112\\ 123 | 53939.2603758079 19.6676345378916 1.02315173365127 1.02315173365127\\ 124 | 130240.937716863 18.3435824135538 0.195735083846963 0.195735083846963\\ 125 | 27281.4692961602 20.8755273958803 3.96092444894359 3.96092444894359\\ 126 | 81017.1760328248 18.9834687699148 0.462576998836875 0.462576998836875\\ 127 | 90129.3849290184 18.7809056600762 0.376175674619081 0.376175674619081\\ 128 | 134854.212682816 18.3289989496668 0.185163179879921 0.185163179879921\\ 129 | 116773.970377645 18.4532827516731 0.235074764576524 0.235074764576524\\ 130 | }; 131 | \addlegendentry{16.6 bar, 55 $^\circ$C} 132 | 133 | \end{axis} 134 | 135 | \begin{axis}[% 136 | % width=8.167in, 137 | % height=7.365in, 138 | % at={(0in,0in)}, 139 | scale only axis, 140 | xmin=0, 141 | xmax=1, 142 | ymin=0, 143 | ymax=1, 144 | axis line style={draw=none}, 145 | ticks=none, 146 | axis x line*=bottom, 147 | axis y line*=left 148 | ] 149 | \end{axis} 150 | \end{tikzpicture}% 151 | -------------------------------------------------------------------------------- /data/matlab2tikz_table_example_data.csv: -------------------------------------------------------------------------------- 1 | Pressure, Temperature, Reynolds, Drag_Coefficient, Drag_Coefficient_Error_Pos, Drag_Coefficient_Error_Neg 2 | 9, 30, 91450.4005348642, 18.8206494302446, 0.22784420833039, 0.22784420833039 3 | 9, 30, 9600.2287009917, 17.0940855567971, 18.8769483727188, 18.8769483727188 4 | 9, 30, 98040.7874556726, 18.6728583096816, 0.202036909770865, 0.202036909770865 5 | 9, 30, 65157.2349669312, 19.3095953696594, 0.418204806276939, 0.418204806276939 6 | 9, 30, 49337.9741089259, 19.8795961310237, 0.722764642682136, 0.722764642682136 7 | 9, 30, 16355.6858822063, 21.6588058718839, 6.48504129977849, 6.48504129977849 8 | 9, 30, 68662.1156767816, 19.2826158073702, 0.379906394244728, 0.379906394244728 9 | 9, 30, 88193.8884388812, 18.8512612583498, 0.241587510229639, 0.241587510229639 10 | 9, 30, 52897.2052503459, 19.7556610691345, 0.63682805169426, 0.63682805169426 11 | 9, 30, 45361.2310463829, 19.9283864286216, 0.857322986465614, 0.857322986465614 12 | 9, 30, 35629.1264772871, 20.5353610928944, 1.37414627818398, 1.37414627818398 13 | 9, 30, 95043.2938482082, 18.7591297797428, 0.213416328531058, 0.213416328531058 14 | 9, 30, 61640.0699375336, 19.465583058119, 0.466703246588861, 0.466703246588861 15 | 9, 30, 58751.4523099524, 19.4914842217088, 0.508777380354382, 0.508777380354382 16 | 9, 30, 41886.8624922781, 20.2213805881069, 0.988945957346638, 0.988945957346638 17 | 9, 30, 71787.1923690876, 19.183171510498, 0.349958881481435, 0.349958881481435 18 | 9, 30, 55566.6189222481, 19.6884300185046, 0.57492765151384, 0.57492765151384 19 | 9, 30, 22414.4905749956, 21.4563894028588, 3.46477796770842, 3.46477796770842 20 | 9, 30, 29891.5116045859, 20.8072061681644, 1.95317002720734, 1.95317002720734 21 | 9, 30, 81648.5561586976, 18.9338775855205, 0.276308105964505, 0.276308105964505 22 | 9, 30, 84915.3205825358, 18.9018965006065, 0.25775055811768, 0.25775055811768 23 | 9, 30, 12748.6992906755, 20.956252098279, 10.6964468685791, 10.6964468685791 24 | 9, 30, 19702.7655801537, 21.3720690437585, 4.47489311485873, 4.47489311485873 25 | 9, 30, 78363.5688516276, 19.0751370068433, 0.297546198952902, 0.297546198952902 26 | 9, 30, 32704.8269868436, 20.8291059476584, 1.63441062956786, 1.63441062956786 27 | 9, 30, 39454.0447791576, 20.3956969160794, 1.11850790152941, 1.11850790152941 28 | 9, 30, 25852.5857440217, 21.5131319639883, 2.60715319679087, 2.60715319679087 29 | 9, 30, 75047.302268985, 19.1129078534408, 0.322186799342343, 0.322186799342343 30 | 13.2, 45, 90364.8194858743, 18.851972315629, 0.305217342375055, 0.305217342375055 31 | 13.2, 45, 8076.2640578434, 24.0111558434839, 35.8029501848227, 35.8029501848227 32 | 13.2, 45, 50772.0591562781, 19.7992917932574, 0.928394801097195, 0.928394801097195 33 | 13.2, 45, 66195.4322434412, 19.2914810641625, 0.550235869227531, 0.550235869227531 34 | 13.2, 45, 47363.6661097263, 20.0685366715685, 1.0630574120011, 1.0630574120011 35 | 13.2, 45, 19902.7764508919, 21.2759580135189, 5.98521694141482, 5.98521694141482 36 | 13.2, 45, 39900.5151261104, 20.5397185970455, 1.48849529409474, 1.48849529409474 37 | 13.2, 45, 74866.732832787, 19.0900594677447, 0.434436734327329, 0.434436734327329 38 | 13.2, 45, 82545.9819399738, 18.9439559950128, 0.361002096005894, 0.361002096005894 39 | 13.2, 45, 106171.719883028, 18.6283535384433, 0.229496342278619, 0.229496342278619 40 | 13.2, 45, 94122.014260214, 18.7599655960001, 0.282619972807026, 0.282619972807026 41 | 13.2, 45, 55431.0307804117, 19.61223734667, 0.783444980800781, 0.783444980800781 42 | 13.2, 45, 59322.7541290298, 19.6319108649163, 0.684931628377185, 0.684931628377185 43 | 13.2, 45, 114221.038645558, 18.4694576373584, 0.203347977101083, 0.203347977101083 44 | 13.2, 45, 78925.5166005358, 19.0282740070502, 0.393135093952, 0.393135093952 45 | 13.2, 45, 63096.2993854333, 19.3936301169532, 0.605948000756784, 0.605948000756784 46 | 13.2, 45, 86358.0944477848, 18.8993234493532, 0.331341638288088, 0.331341638288088 47 | 13.2, 45, 110454.377590452, 18.567036984956, 0.214660611248231, 0.214660611248231 48 | 13.2, 45, 35864.0452240558, 20.7795087552391, 1.84052287954811, 1.84052287954811 49 | 13.2, 45, 102270.885599624, 18.6534024509903, 0.244662856478561, 0.244662856478561 50 | 13.2, 45, 15625.3491197509, 23.0212986293325, 9.68121139016299, 9.68121139016299 51 | 13.2, 45, 98275.2673711873, 18.6797685109276, 0.262281703155193, 0.262281703155193 52 | 13.2, 45, 31352.5742431042, 21.0124223239215, 2.41763424066977, 2.41763424066977 53 | 13.2, 45, 12313.9582502865, 22.5336653922509, 15.5170405633573, 15.5170405633573 54 | 13.2, 45, 118521.184105338, 18.4634946805162, 0.191715543444072, 0.191715543444072 55 | 13.2, 45, 27954.591413931, 21.1733665963443, 3.03909219686198, 3.03909219686198 56 | 13.2, 45, 23661.526874057, 21.8398598857805, 4.23960949267591, 4.23960949267591 57 | 13.2, 45, 70936.4289641694, 19.2203716274935, 0.481640104330054, 0.481640104330054 58 | 13.2, 45, 43616.6098039867, 20.3724031756756, 1.24623498410928, 1.24623498410928 59 | 16.6, 55, 17867.5515609687, 21.7652508894877, 9.15368581910848, 9.15368581910848 60 | 16.6, 55, 125637.055996345, 18.3877470989716, 0.20747930927834, 0.20747930927834 61 | 16.6, 55, 49304.731241175, 19.807149989706, 1.22247182825836, 1.22247182825836 62 | 16.6, 55, 107667.483438579, 18.6074812032667, 0.27078355428531, 0.27078355428531 63 | 16.6, 55, 13536.3513622991, 22.9216117473262, 16.0120267998002, 16.0120267998002 64 | 16.6, 55, 71994.5089139876, 19.1461599074966, 0.579982264504498, 0.579982264504498 65 | 16.6, 55, 58949.4992802703, 19.4584247735011, 0.863655495599455, 0.863655495599455 66 | 16.6, 55, 22441.0358182932, 20.9345419939241, 5.80047673858736, 5.80047673858736 67 | 16.6, 55, 44296.5080074942, 19.8307916472566, 1.50683347198268, 1.50683347198268 68 | 16.6, 55, 36163.6188854124, 20.1076548679491, 2.265078120627, 2.265078120627 69 | 16.6, 55, 121252.135326159, 18.4363699283627, 0.220566362796363, 0.220566362796363 70 | 16.6, 55, 85072.0354168332, 18.8324850607434, 0.418963400171204, 0.418963400171204 71 | 16.6, 55, 103030.125538593, 18.6109968334098, 0.292673058569925, 0.292673058569925 72 | 16.6, 55, 62664.4453756571, 19.3182930613143, 0.76166308494462, 0.76166308494462 73 | 16.6, 55, 66814.802347003, 19.1511266386389, 0.671621933741905, 0.671621933741905 74 | 16.6, 55, 40023.6860323227, 20.3563108994464, 1.84868057936682, 1.84868057936682 75 | 16.6, 55, 98428.0786967929, 18.7052786521598, 0.318212576297495, 0.318212576297495 76 | 16.6, 55, 94101.3387888276, 18.7365240146046, 0.345945890970535, 0.345945890970535 77 | 16.6, 55, 112249.405136342, 18.541593643746, 0.2517944419942, 0.2517944419942 78 | 16.6, 55, 31272.4427821611, 20.5767680935139, 3.01988954371356, 3.01988954371356 79 | 16.6, 55, 76452.8638484087, 19.0625190030148, 0.518185514149112, 0.518185514149112 80 | 16.6, 55, 53939.2603758079, 19.6676345378916, 1.02315173365127, 1.02315173365127 81 | 16.6, 55, 130240.937716863, 18.3435824135538, 0.195735083846963, 0.195735083846963 82 | 16.6, 55, 27281.4692961602, 20.8755273958803, 3.96092444894359, 3.96092444894359 83 | 16.6, 55, 81017.1760328248, 18.9834687699148, 0.462576998836875, 0.462576998836875 84 | 16.6, 55, 90129.3849290184, 18.7809056600762, 0.376175674619081, 0.376175674619081 85 | 16.6, 55, 134854.212682816, 18.3289989496668, 0.185163179879921, 0.185163179879921 86 | 16.6, 55, 116773.970377645, 18.4532827516731, 0.235074764576524, 0.235074764576524 87 | -------------------------------------------------------------------------------- /images/bitmaps/README.md: -------------------------------------------------------------------------------- 1 | # Bitmaps Graphics Directory 2 | 3 | This directory holds bitmaps (JPG, PNG, ...), to be used with `\includegraphics{}`. 4 | If there's a file `abc` in here, include it in the document with `\includegraphics{abc}`: 5 | 6 | - no leading path (`includegraphics` knows to look in here), 7 | - no file suffix (`includegraphics` looks for the common ones automatically). 8 | 9 | **PDFs files (even if they're vectors) also go in here** and are usable via `\includegraphics` in the same way. 10 | -------------------------------------------------------------------------------- /images/bitmaps/field.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexpovel/latex-cookbook/ef414c2ca316dad2cd8dc904f29346aeda39990d/images/bitmaps/field.jpg -------------------------------------------------------------------------------- /images/bitmaps/readme/backref.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexpovel/latex-cookbook/ef414c2ca316dad2cd8dc904f29346aeda39990d/images/bitmaps/readme/backref.png -------------------------------------------------------------------------------- /images/bitmaps/readme/chem.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexpovel/latex-cookbook/ef414c2ca316dad2cd8dc904f29346aeda39990d/images/bitmaps/readme/chem.png -------------------------------------------------------------------------------- /images/bitmaps/readme/code.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexpovel/latex-cookbook/ef414c2ca316dad2cd8dc904f29346aeda39990d/images/bitmaps/readme/code.png -------------------------------------------------------------------------------- /images/bitmaps/readme/font-shapes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexpovel/latex-cookbook/ef414c2ca316dad2cd8dc904f29346aeda39990d/images/bitmaps/readme/font-shapes.png -------------------------------------------------------------------------------- /images/bitmaps/readme/language.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexpovel/latex-cookbook/ef414c2ca316dad2cd8dc904f29346aeda39990d/images/bitmaps/readme/language.png -------------------------------------------------------------------------------- /images/bitmaps/readme/math-macros.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexpovel/latex-cookbook/ef414c2ca316dad2cd8dc904f29346aeda39990d/images/bitmaps/readme/math-macros.png -------------------------------------------------------------------------------- /images/bitmaps/readme/math.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexpovel/latex-cookbook/ef414c2ca316dad2cd8dc904f29346aeda39990d/images/bitmaps/readme/math.png -------------------------------------------------------------------------------- /images/bitmaps/readme/plot-compute.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexpovel/latex-cookbook/ef414c2ca316dad2cd8dc904f29346aeda39990d/images/bitmaps/readme/plot-compute.png -------------------------------------------------------------------------------- /images/bitmaps/readme/plot-csv.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexpovel/latex-cookbook/ef414c2ca316dad2cd8dc904f29346aeda39990d/images/bitmaps/readme/plot-csv.png -------------------------------------------------------------------------------- /images/bitmaps/readme/tables.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexpovel/latex-cookbook/ef414c2ca316dad2cd8dc904f29346aeda39990d/images/bitmaps/readme/tables.png -------------------------------------------------------------------------------- /images/bitmaps/readme/tikz-annotations.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexpovel/latex-cookbook/ef414c2ca316dad2cd8dc904f29346aeda39990d/images/bitmaps/readme/tikz-annotations.png -------------------------------------------------------------------------------- /images/bitmaps/readme/tikz-diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexpovel/latex-cookbook/ef414c2ca316dad2cd8dc904f29346aeda39990d/images/bitmaps/readme/tikz-diagram.png -------------------------------------------------------------------------------- /images/bitmaps/readme/tikz-libraries.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexpovel/latex-cookbook/ef414c2ca316dad2cd8dc904f29346aeda39990d/images/bitmaps/readme/tikz-libraries.png -------------------------------------------------------------------------------- /images/bitmaps/svg_tikz_example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexpovel/latex-cookbook/ef414c2ca316dad2cd8dc904f29346aeda39990d/images/bitmaps/svg_tikz_example.png -------------------------------------------------------------------------------- /images/bitmaps/svg_tikz_example_debug.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexpovel/latex-cookbook/ef414c2ca316dad2cd8dc904f29346aeda39990d/images/bitmaps/svg_tikz_example_debug.png -------------------------------------------------------------------------------- /images/vectors/README.md: -------------------------------------------------------------------------------- 1 | # Vector Graphics Directory 2 | 3 | This directory holds vector graphics SVG files, to be used with `\includesvg{}`. 4 | If there's a file `abc` in here, include it in the document with `\includesvg{abc}`: 5 | 6 | - no leading path (`includesvg` knows to look in here), 7 | - no file suffix (`includesvg` can only handle `.svg` anyway). 8 | -------------------------------------------------------------------------------- /images/vectors/logos/matlab_simulink/matlab_object_box.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 20 | 22 | 25 | 29 | 33 | 34 | 37 | 41 | 45 | 46 | 53 | 62 | 72 | 73 | 104 | 109 | 110 | 112 | 113 | 115 | image/svg+xml 116 | 118 | 119 | 120 | 121 | 122 | 128 | 134 | 143 | 149 | 155 | 156 | 157 | -------------------------------------------------------------------------------- /images/vectors/logos/matlab_simulink/matlab_struct.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 20 | 22 | 25 | 29 | 33 | 34 | 44 | 45 | 76 | 81 | 86 | 87 | 89 | 90 | 92 | image/svg+xml 93 | 95 | 96 | 97 | 98 | 99 | 104 | 109 | 112 | 121 | 127 | 133 | 139 | 145 | 146 | 147 | 148 | -------------------------------------------------------------------------------- /images/vectors/logos/matlab_simulink/matlab_table.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 20 | 22 | 25 | 29 | 33 | 34 | 44 | 54 | 64 | 65 | 96 | 101 | 106 | 107 | 109 | 110 | 112 | image/svg+xml 113 | 115 | 116 | 117 | 118 | 119 | 125 | 131 | 140 | 146 | 156 | 162 | 168 | 177 | 183 | 189 | 190 | 191 | -------------------------------------------------------------------------------- /images/vectors/logos/matlab_simulink/simulink_base_workspace.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 20 | 22 | 25 | 29 | 33 | 34 | 44 | 45 | 75 | 77 | 78 | 80 | image/svg+xml 81 | 83 | 84 | 85 | 86 | 87 | 92 | 97 | 100 | 109 | 114 | 119 | 120 | 121 | 122 | -------------------------------------------------------------------------------- /images/vectors/logos/matlab_simulink/simulink_configuration.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 20 | 49 | 51 | 54 | 58 | 62 | 63 | 66 | 70 | 74 | 75 | 85 | 94 | 103 | 104 | 106 | 107 | 109 | image/svg+xml 110 | 112 | 113 | 114 | 115 | 116 | 122 | 128 | 133 | 139 | 140 | 146 | 152 | 153 | 154 | -------------------------------------------------------------------------------- /images/vectors/logos/matlab_simulink/simulink_data_dictionary.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 20 | 22 | 25 | 29 | 33 | 34 | 43 | 44 | 71 | 73 | 74 | 76 | image/svg+xml 77 | 79 | 80 | 81 | 82 | 83 | 89 | 94 | 97 | 103 | 109 | 115 | 121 | 122 | 123 | 124 | -------------------------------------------------------------------------------- /images/vectors/logos/matlab_simulink/simulink_library.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 20 | 22 | 32 | 35 | 39 | 43 | 44 | 53 | 56 | 60 | 64 | 65 | 75 | 78 | 82 | 86 | 87 | 88 | 118 | 120 | 121 | 123 | image/svg+xml 124 | 126 | 127 | 128 | 129 | 130 | 135 | 140 | 149 | 154 | 171 | 180 | 181 | 182 | -------------------------------------------------------------------------------- /images/vectors/logos/matlab_simulink/simulink_library_model.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 19 | 21 | 46 | 48 | 49 | 51 | image/svg+xml 52 | 54 | 55 | 56 | 57 | 58 | 63 | 68 | 71 | 80 | 86 | 92 | 93 | 94 | 95 | -------------------------------------------------------------------------------- /images/vectors/logos/matlab_simulink/simulink_log_data.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 20 | 22 | 25 | 29 | 33 | 34 | 44 | 53 | 63 | 64 | 91 | 93 | 94 | 96 | image/svg+xml 97 | 99 | 100 | 101 | 102 | 103 | 108 | 114 | 126 | 138 | 139 | 140 | -------------------------------------------------------------------------------- /images/vectors/logos/matlab_simulink/simulink_lut.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 20 | 22 | 25 | 29 | 33 | 34 | 44 | 54 | 55 | 85 | 87 | 88 | 90 | image/svg+xml 91 | 93 | 94 | 95 | 96 | 97 | 103 | 109 | 111 | 120 | 126 | 132 | 138 | 144 | 145 | 146 | 147 | -------------------------------------------------------------------------------- /images/vectors/logos/matlab_simulink/simulink_model.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 20 | 22 | 32 | 35 | 39 | 43 | 44 | 53 | 56 | 60 | 64 | 65 | 75 | 78 | 82 | 86 | 87 | 88 | 118 | 120 | 121 | 123 | image/svg+xml 124 | 126 | 127 | 128 | 129 | 130 | 135 | 140 | 143 | 152 | 157 | 174 | 183 | 184 | 185 | 186 | -------------------------------------------------------------------------------- /images/vectors/logos/matlab_simulink/simulink_model_workspace.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 20 | 22 | 25 | 29 | 33 | 34 | 37 | 41 | 45 | 46 | 49 | 53 | 57 | 58 | 61 | 65 | 69 | 70 | 80 | 90 | 99 | 109 | 110 | 140 | 142 | 143 | 145 | image/svg+xml 146 | 148 | 149 | 150 | 151 | 152 | 157 | 162 | 165 | 174 | 179 | 184 | 185 | 188 | 197 | 202 | 219 | 228 | 229 | 230 | 231 | -------------------------------------------------------------------------------- /images/vectors/logos/matlab_simulink/simulink_referenced_model.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 20 | 22 | 25 | 29 | 33 | 34 | 44 | 45 | 69 | 71 | 72 | 74 | image/svg+xml 75 | 77 | 78 | 79 | 80 | 81 | 86 | 91 | 100 | 105 | 110 | 115 | 120 | 121 | 122 | -------------------------------------------------------------------------------- /images/vectors/logos/matlab_simulink/simulink_step_block.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 19 | 21 | 45 | 47 | 48 | 50 | image/svg+xml 51 | 53 | 54 | 55 | 56 | 57 | 62 | 71 | 80 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /lib/README.md: -------------------------------------------------------------------------------- 1 | # Library code 2 | 3 | This directory might contain, for example: 4 | 5 | - Lua files for usage alongside `lualatex`. 6 | Embedding Lua for `lualatex` to consume is quite powerful and neat, and we are gladly making use of it. 7 | However, embedding Lua verbatim into `\directlua` is a bit ugly [and has annoying issues with escaping](https://web.archive.org/web/20210208133949if_/https://www.overleaf.com/learn/latex/Articles/An_Introduction_to_LuaTeX_(Part_2):_Understanding_%5Cdirectlua). 8 | Therefore, prefer to load external, proper Lua files using `\dofile`. 9 | These files might live in here, if required. 10 | - Outsourced LaTeX source code that is better off modularized, like custom packages. 11 | -------------------------------------------------------------------------------- /lib/example.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | The following import is not required since in LuaTeX's `\directlua` environment, 3 | `token` etc. is already available. However, this is nice to keep linters from 4 | complaining about an undefined variable. 5 | --]] 6 | local token = require("token") 7 | local texio = require("texio") 8 | local status = require("status") 9 | 10 | --[[ 11 | Trying to incorporate dynamic values into certain newcommand macros. Their 12 | contents are set at build-time according to environment variables. This is useful 13 | for automatic workflows in CI environments. See also: 14 | https://tex.stackexchange.com/a/1739/120853. 15 | An alternative to using environment variables are command line arguments: 16 | https://tex.stackexchange.com/a/18813/120853 17 | However, this seems more error-prone and requires more steps, e.g. piping arguments 18 | to `lualatex` through `latexmk` first, etc. 19 | The previous approach was to `sed` for certain `newcommand` definitions in an 20 | additional CI job. This was much more error-prone (bash scripting) and less 21 | easily expanded than the below approach. 22 | LuaTeX provides excellent access to TeX, making this implementation much easier. 23 | --]] 24 | 25 | local function get_cmd_stdout(cmd) 26 | -- See: https://stackoverflow.com/a/326715/11477374 27 | local fh = assert(io.popen(cmd)) 28 | local first_line = assert(fh:read()) 29 | fh:close() 30 | return first_line 31 | end 32 | 33 | -- Environment variables as used e.g. in GitLab CI. 34 | -- Otherwise, e.g. when developing locally, use commands as a fallback. 35 | local macro_content_sources = { 36 | GitRefName = { 37 | env = "CI_COMMIT_REF_NAME", 38 | cmd = "git rev-parse --abbrev-ref HEAD", 39 | }, 40 | GitShortSHA = { 41 | env = "CI_COMMIT_SHORT_SHA", 42 | cmd = "git rev-parse --short HEAD", 43 | }, 44 | } 45 | 46 | for macro_name, content_sources in pairs(macro_content_sources) do 47 | -- Default: check for environment variable: 48 | local env = content_sources.env 49 | local cmd = content_sources.cmd 50 | local content = "n.a." -- Default value 51 | local env_content = os.getenv(env) 52 | 53 | if env_content and env_content ~= "" then -- Empty string evaluates to true 54 | texio.write_nl("Found and will be using environment variable '"..env.."'.") 55 | content = env_content 56 | else 57 | texio.write_nl("Environment variable '"..env.."' undefined or empty, trying fallback command.") 58 | -- luatex reference for shell escape: 59 | -- "0 means disabled, 1 means anything is permitted, and 2 is restricted" 60 | if status.shell_escape == 1 then 61 | local cmd_success, cmd_stdout = pcall(get_cmd_stdout, cmd) 62 | if cmd_success then 63 | texio.write_nl("Fallback command '"..cmd.."' succeeded.") 64 | content = cmd_stdout 65 | else 66 | texio.write_nl("Fallback command '"..cmd.."' unsuccessful.") 67 | end 68 | else 69 | texio.write_nl("shell-escape is disabled, cannot use fallback command.") 70 | end 71 | end 72 | 73 | -- Shouldn't happen, would be programmer error, therefore assert Python-style 74 | assert(content, "Content not defined (neither success nor fallback present)") 75 | 76 | --[[ 77 | The `content` can contain unprintable characters, like underscores in git branch 78 | names. Towards this end, use detokenize in the macro itself, which will make all 79 | characters printable (assigns category code 12). See also: 80 | https://www.overleaf.com/learn/latex/Articles/An_Introduction_to_LuaTeX_(Part_2):_Understanding_%5Cdirectlua 81 | --]] 82 | local escaped_content = "\\detokenize{"..content.."}" 83 | 84 | texio.write_nl("Providing new macro '"..macro_name.."' with contents: '"..escaped_content.."'.") 85 | -- Set a macro (`\newcommand`) see also: https://tex.stackexchange.com/a/450892/120853 86 | token.set_macro(macro_name, escaped_content) 87 | end 88 | -------------------------------------------------------------------------------- /pandoc/README.md: -------------------------------------------------------------------------------- 1 | # Pandoc 2 | 3 | `pandoc` is a tool almost completely separate from LaTeX, but goes hand-in-hand with it. 4 | It is not relevant to the main project and used here only as an interesting showcase on how to convert Markdown READMEs to PDF (which uses LaTeX in the background). 5 | This directory contains configuration files for `pandoc`. 6 | -------------------------------------------------------------------------------- /pandoc/defaults.yaml: -------------------------------------------------------------------------------- 1 | # Instead of command-line options, configure pandoc here and point it to this file. 2 | # See also: https://pandoc.org/MANUAL.html#default-files 3 | 4 | # ------------------------------------------------------------------------------------- 5 | # Basics 6 | # ------------------------------------------------------------------------------------- 7 | # lualatex for Unicode and all the other good stuff. Better than xelatex and pdflatex. 8 | pdf-engine: lualatex 9 | 10 | # When calling `pandoc` from this project's root using `--defaults=subdir/defaults.yaml`, 11 | # the filter filters are resolved in relation to where `pandoc` is called, NOT relative 12 | # to the `defaults.yaml` file. 13 | # The same is true for metadata files. 14 | # Therefore, keep this ugly hack (specifying paths relative to project root dir) 15 | # until https://github.com/jgm/pandoc/issues/5982 is resolved: 16 | metadata-file: pandoc/metadata.yaml 17 | 18 | # Custom filter programs modify the document (pandoc AST) before it is written out: 19 | filters: 20 | - pandoc/promote-headers.lua 21 | 22 | # ------------------------------------------------------------------------------------- 23 | # Style 24 | # ------------------------------------------------------------------------------------- 25 | # Core pandoc options, see https://pandoc.org/MANUAL.html#default-files: 26 | table-of-contents: true 27 | number-sections: true 28 | 29 | template: eisvogel 30 | variables: 31 | # These are used by the Eisvogel pandoc template, i.e. not by core pandoc itself. 32 | # See also https://github.com/Wandmalfarbe/pandoc-latex-template#custom-template-variables 33 | titlepage: true 34 | colorlinks: true 35 | lang: "en" 36 | # ------------------------------------------------------------------------------------- 37 | # Other 38 | # ------------------------------------------------------------------------------------- 39 | # ERROR, WARNING, INFO: 40 | verbosity: WARNING 41 | -------------------------------------------------------------------------------- /pandoc/metadata.yaml: -------------------------------------------------------------------------------- 1 | author: [Alex Povel] 2 | subject: "Advantages of a workflow using LaTeX with GitLab, GitHub Actions etc." 3 | keywords: [LaTeX, CI, CD, Markdown] 4 | -------------------------------------------------------------------------------- /pandoc/promote-headers.lua: -------------------------------------------------------------------------------- 1 | -- From https://stackoverflow.com/a/56005271/11477374: 2 | -- Automatically get "Document Title" from Markdown top-level heading by promoting all 3 | -- headings one level up (for Markdown, # becomes %, ## becomes # etc.). 4 | -- See also: 5 | -- https://github.com/jgm/pandoc/issues/5615 6 | 7 | -- Stop linters from complaining about missing variable: 8 | local pandoc = require("pandoc") 9 | 10 | local title 11 | 12 | -- Promote all headers by one level. Set title from level 1 headers, 13 | -- unless it has been set before. 14 | function promote_header (header) 15 | 16 | if header.level >= 2 then 17 | header.level = header.level - 1 18 | return header 19 | end 20 | 21 | if not title then 22 | title = header.content 23 | return {} 24 | end 25 | 26 | local msg = '[WARNING] title already set; discarding header "%s"\n' 27 | io.stderr:write(msg:format(pandoc.utils.stringify(header))) 28 | return {} 29 | end 30 | 31 | return { 32 | {Meta = function (meta) title = meta.title end}, -- init title 33 | {Header = promote_header}, 34 | {Meta = function (meta) meta.title = title; return meta end}, -- set title 35 | } 36 | -------------------------------------------------------------------------------- /tests/Makefile: -------------------------------------------------------------------------------- 1 | # Get this file's directory, allows this Makefile to be run on its own or via 2 | # `include` from a root Makefile. From: 3 | # https://www.systutorials.com/how-to-get-a-makefiles-directory-for-including-other-makefiles/ 4 | SELF_DIR = $(dir $(lastword $(MAKEFILE_LIST))) 5 | 6 | # No Docker image available for this yet. Refer to the CI config to configure this for 7 | # local use. 8 | TEST = poetry run pytest 9 | TESTS_DIR = tests 10 | 11 | .PHONY: test test-self test-pdfs 12 | 13 | define run_test 14 | cd $(SELF_DIR) && \ 15 | $(TEST) $(TESTS_DIR)/$(subst -,_,$(1)).py $(TEST_FLAGS) 16 | endef 17 | 18 | ifdef CI 19 | TEST_FLAGS = --verbose 20 | else 21 | TEST_FLAGS = 22 | endif 23 | 24 | test: test-self test-pdfs # Runs all tests. 25 | @echo "All tests passed." 26 | 27 | # Target names correspond to actual Python test files, with some modifications made, see 28 | # the `run_test` function. 29 | 30 | test-self: # Runs tests on the tests themselves. 31 | @$(call run_test,$@) 32 | 33 | test-pdfs: # Runs tests on found PDFs. 34 | @$(call run_test,$@) 35 | -------------------------------------------------------------------------------- /tests/README.md: -------------------------------------------------------------------------------- 1 | # Automated Testing 2 | 3 | This sub-project contains Python-based code for testing the PDF output produced by 4 | earlier CI stages, or by you locally. 5 | 6 | The desired properties of the PDFs under test (by default, all PDFs in the project root), 7 | are configured in the [tests config file](config.yml). 8 | Once that is done to your liking, [set up the testing framework](#setup) and [run](#running) 9 | the tests (or don't and use CI instead, where everything is done for you already and 10 | Just Works™). 11 | 12 | This is helpful to check for basic stuff. 13 | A more involved approach is shown [here](https://blog.martisak.se/2020/05/16/latex-test-cases/). 14 | This includes checking for publisher-specific requirements, allowing us to detect errors 15 | and iterate much faster. 16 | 17 | ## Setup 18 | 19 | There are two steps to this. 20 | This is unfortunately not as easy as it could be, owed to the nature of Python's 21 | ecosystem. 22 | 23 | ### Python dependencies 24 | 25 | The project uses [poetry](https://python-poetry.org/docs/#installation) for dependency 26 | management. 27 | Once you have it installed according to their documentation, it is very easy to pull in 28 | the dependencies of this project. 29 | In the directory containing [the `poetry` config file](pyproject.toml), run 30 | 31 | ```bash 32 | poetry install 33 | ``` 34 | 35 | This will pull the precise requirements needed from the [lock file](poetry.lock). 36 | Otherwise, it uses the config file. 37 | That's it... almost. 38 | 39 | ### Python itself 40 | 41 | You will also need a suitable Python interpreter, aka Python version. 42 | This is "Python itself". 43 | If your system's Python *is* compatible with what is listed in the [config](pyproject.toml), 44 | you do not need to do anything. 45 | The easiest way to test this is to just run: 46 | 47 | ```bash 48 | poetry run pytest 49 | ``` 50 | 51 | and see if it fails. 52 | If it does, `poetry` will complain to you accordingly. 53 | In such a case, [`pyenv`](https://github.com/pyenv/pyenv) has worked well for me to set 54 | up a suitable, local or system-wide Python interpreter of *any* desired version. 55 | 56 | The setup for the CI pipeline (GitHub Actions) is quite different. 57 | Take a look if you like, but the steps there are not applicable to local usage. 58 | 59 | ## Running 60 | 61 | After the setup, you can simply run: 62 | 63 | ```bash 64 | poetry run pytest 65 | ``` 66 | 67 | Prepending everything with `poetry run` will make sure all commands run in the suitable 68 | [virtual environment](https://docs.python.org/3/tutorial/venv.html) with the correct 69 | packages installed in the correct versions, as well as using the Python version set up 70 | using `pyenv`, if any. 71 | 72 | Any sub-commands or flags after `pytest` are courtesy of `pytest`, not `poetry`. 73 | There, you can for example specify which tests to run. 74 | 75 | ### Makefile 76 | 77 | Otherwise, the testing procedure is tucked away and made accessible via the [Makefile](Makefile). 78 | It requires you to have [GNU `make`](https://www.gnu.org/software/make/) installed. 79 | If you are on Linux you might already have it, since a lot of development workflows rely 80 | on it. 81 | The tests can then be run using: 82 | 83 | ```bash 84 | make test 85 | ``` 86 | 87 | or any of the other *targets* in that Makefile: 88 | 89 | ```bash 90 | make test-self 91 | make test-pdfs 92 | ``` 93 | 94 | ## Side note 95 | 96 | Sadly, an inherent issue is that [PDF parsing/text extraction](https://news.ycombinator.com/item?id=22473263) 97 | is incredibly hard. 98 | Visually, PDFs might look fine to human eyes, but trying to tell a computer, in an 99 | automated fashion, what *it* sees and have it parse that correctly is as of today 100 | basically impossible. 101 | -------------------------------------------------------------------------------- /tests/config.yml: -------------------------------------------------------------------------------- 1 | metadata: 2 | encryption: null # why tho 3 | pdf_version: "1.5" # Versions are strings, not floats (see semantic versioning) 4 | 5 | pages: 6 | n_min: 1 7 | n_max: null # Null will ignore this boundary 8 | papersize: 9 | # This is either a mapping of .pdf to , or one value for 10 | # *all* PDFs, for example: `papersize: "a4"`. 11 | # Possible values: https://papersize.readthedocs.io/en/latest/#papersize.parse_papersize 12 | cookbook: "a4" 13 | README: "a4" 14 | 15 | file: 16 | # File sizes in human-readable format, or null to ignore. 17 | min_size: "10K" # Some rough minimum, maybe useful to detect corrupted files 18 | max_size: "5M" 19 | bookmarks: true # Check if those are present 20 | # For age, d, h, m and s (or null to skip test) are available. Order matters. 21 | # Could be useful to detect old files that crept in, e.g. from a cache. 22 | max_age: null 23 | 24 | content: 25 | required_strings: null 26 | -------------------------------------------------------------------------------- /tests/pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry] 2 | name = "tests" 3 | version = "4.0.0" 4 | description = "Checks for PDFs." 5 | authors = ["Alex Povel "] 6 | 7 | [tool.poetry.dependencies] 8 | python = "^3.10" 9 | pymupdf = "^1.19.0" 10 | pytest = "^7.4.0" 11 | PyYAML = "^6.0" 12 | python-dateutil = "^2.8.1" 13 | PaperSize = "^1.3.0" 14 | 15 | [tool.poetry.dev-dependencies] 16 | ipython = "^8.14.0" 17 | black = "^23.7" 18 | 19 | [build-system] 20 | requires = ["poetry>=0.12"] 21 | build-backend = "poetry.masonry.api" 22 | -------------------------------------------------------------------------------- /tests/tests/__init__.py: -------------------------------------------------------------------------------- 1 | """Strictly required for `pytest` to find this Python package and import from it.""" 2 | -------------------------------------------------------------------------------- /tests/tests/conftest.py: -------------------------------------------------------------------------------- 1 | """File to configure pytest, e.g. to implement hooks. 2 | See also: https://stackoverflow.com/q/34466027/11477374 3 | List of hooks: https://pytest.org/en/latest/reference.html#hook-reference 4 | """ 5 | 6 | from tests.utils import _PROJECT_ROOT 7 | 8 | 9 | def pytest_make_parametrize_id(config, val, argname): 10 | """Provide IDs aka names for test cases. 11 | pytest generates automatic IDs. Using this function, they can be altered to 12 | whatever more legible representation, see 13 | https://doc.pytest.org/en/latest/example/parametrize.html#different-options-for-test-ids. 14 | Implementing this function in a specific file using a specific name will hook it 15 | into pytest and use it for *all* ID generation automatically, so no need to specify 16 | `ids=` all the time. 17 | Demo: https://raphael.codes/blog/ids-for-pytest-fixtures-and-parametrize/ 18 | """ 19 | try: 20 | # Shorten filepath significantly, in relation to project root. 21 | val = val.relative_to(_PROJECT_ROOT) 22 | except AttributeError: 23 | pass 24 | return str(val) 25 | -------------------------------------------------------------------------------- /tests/tests/test_pdfs.py: -------------------------------------------------------------------------------- 1 | """Tests whether PDFs documents fulfill certain criteria. 2 | 3 | This is a bit backwards: `pytest` ordinarily tests functions/units, with sample data 4 | being generated as needed. This module tests *data*, not the logic working on them. 5 | For this, a package like `datatest` is maybe more suitable. However, the framework 6 | provided by `pytest` works just fine. It gets us pretty summaries and the like, much 7 | better than crafting that ourselves. 8 | One core downside is that there is way too much logic in the tests themselves, with 9 | no way of testing the tests that test the data. If these are wrong (likelihood increases 10 | with more complexity), we are in for a bad time. 11 | 12 | Idea from: https://blog.martisak.se/2020/05/16/latex-test-cases/ 13 | """ 14 | 15 | import math 16 | from collections import namedtuple 17 | from datetime import datetime as dt 18 | from pathlib import Path 19 | from typing import List 20 | from warnings import warn 21 | 22 | import fitz # PyMuPDF 23 | import pytest 24 | import yaml # PyYAML 25 | from dateutil.parser import parse as parse_date 26 | from papersize import parse_papersize 27 | 28 | from tests.utils import ( 29 | fix_tzoffset, 30 | parse_duration, 31 | parse_size, 32 | _PROJECT_ROOT, 33 | ) 34 | 35 | # Monkey-patch a new, prettier property to access a page's text, instead of calling the 36 | # camelCase method. PEP-8 for the win. 37 | fitz.Page.text = property(lambda self: self.getText()) 38 | fitz.Document.toc = property(lambda self: self.getToC()) 39 | 40 | Rect = namedtuple("Rect", ["width", "height"]) 41 | 42 | 43 | def get_project_root_files(suffix: str) -> List[Path]: 44 | yield from _PROJECT_ROOT.glob("*." + suffix) 45 | 46 | 47 | @pytest.fixture 48 | def config(): 49 | with open(_PROJECT_ROOT / "tests" / "config.yml") as f: 50 | return yaml.safe_load(f) 51 | 52 | 53 | @pytest.fixture(params=get_project_root_files("pdf")) 54 | def pdf(request): # HAS to be named 'request' 55 | doc = fitz.open(request.param) 56 | # Context manager doesn't work, it closes too soon. 57 | yield doc 58 | doc.close() 59 | 60 | 61 | def test_page_numbers(pdf, config): 62 | """Tests that number of pages is within limits. 63 | 64 | Zero-length PDFs don't exist, but perhaps some form of file corruption could produce 65 | them. 66 | """ 67 | n = len(pdf) 68 | 69 | page_config = config["pages"] 70 | n_min = page_config["n_min"] or 1 71 | n_max = page_config["n_max"] or math.inf 72 | 73 | msg = ( 74 | f"Document page count out of bounds: {n} pages not within {n_min} and {n_max}." 75 | ) 76 | assert n_min <= n <= n_max, msg 77 | 78 | 79 | @pytest.mark.skip(reason="README doesn't have bookmarks, but no one cares.") 80 | def test_bookmarks(pdf, config): 81 | """Checks if a table of contents (ToC) is present.""" 82 | bookmarks = config["file"]["bookmarks"] 83 | not_ = "\b" if bookmarks else "not" # ASCII backspace, remove on space char 84 | assert bool(pdf.toc) == bool( 85 | bookmarks 86 | ), f"Bookmarks presence {not_} requested, but opposite found." 87 | 88 | 89 | def test_required_strings(pdf, config): 90 | """Tests whether each required text is found in the document.""" 91 | content_config = config["content"] 92 | for text in content_config["required_strings"] or []: 93 | hits = sum(text in page.text for page in pdf) 94 | assert hits, f"Text '{text}' not found in document." 95 | 96 | 97 | def test_file_size(pdf, config): 98 | """Tests that filesize is within limits.""" 99 | file_config = config["file"] 100 | size = Path(pdf.name).stat().st_size 101 | min_size = parse_size(file_config["min_size"]) or 0 102 | max_size = parse_size(file_config["max_size"]) or math.inf 103 | assert min_size <= size <= max_size 104 | 105 | 106 | def test_metadata(pdf, config): 107 | """Tests file metadata.""" 108 | meta_config = config["metadata"] 109 | 110 | expectations = { # Fields as returned by `fitz.Document.metadata` 111 | "encryption": meta_config["encryption"], 112 | "format": f"PDF {meta_config['pdf_version']}", 113 | } 114 | 115 | for field, content in pdf.metadata.items(): 116 | try: 117 | expectation = expectations[field] 118 | except KeyError: 119 | # Couldn't get successfully, no expected value present. However, the 120 | # user might still want to be warned about empty metadata fields. 121 | if not content: 122 | warn(f"File metadata field '{field}' is empty.") 123 | else: 124 | msg = f"Field '{field}' is '{content}', not '{expectation}'." 125 | assert content == expectation, msg 126 | 127 | 128 | def test_freshness(pdf, config): 129 | """Tests if file is recently created or stale (e.g. from cache). 130 | 131 | If file was fetched from e.g. a CI cache and not regenerated properly, it's a 132 | warning sign. 133 | 134 | `fitz.Document.metadata` dates look like: "D:20201103155304+01'00'". 135 | """ 136 | max_age = config["file"]["max_age"] 137 | if max_age is None: 138 | pytest.skip("No maximum age set, skipping.") 139 | 140 | max_age = parse_duration(max_age) 141 | 142 | categories = ["mod", "creation"] 143 | prefix = "D:" # No idea what it stands for 144 | 145 | dates = {} 146 | for cat in categories: 147 | date = pdf.metadata[cat + "Date"] 148 | date = fix_tzoffset(date) 149 | # In Python 3.9, we would use `str.removeprefix`: 150 | dates[cat] = parse_date(date[len(prefix) :]) 151 | 152 | assert dates["mod"] == dates["creation"], f"Modification and Creation dates differ." 153 | # From here, both dates are equal, so it doesn't matter which we work with. 154 | date = dates["mod"] 155 | 156 | now = dt.now() 157 | try: 158 | file_age = now - date 159 | except TypeError: # can't subtract offset-naive and offset-aware datetimes 160 | file_age = now.astimezone() - date 161 | 162 | # Multiple asserts per unit test is terrible, but so is this entire thing. 163 | assert file_age <= max_age, f"File is older than {max_age}" 164 | 165 | 166 | def test_page_size(pdf, config): 167 | """Tests if all pages sizes are within allowed bounds. 168 | 169 | We require some rounding black-magic, since page dimensions in pt deviate between 170 | official definitions and what the used packages return from the metadata. 171 | """ 172 | size = config["pages"]["papersize"] 173 | if size is None: 174 | pytest.skip("No page size specified, skipping.") 175 | 176 | unit = "cm" # Cast to same unit for comparison 177 | tolerance = 0.01 # Tolerance for value comparison 178 | 179 | # When rounding for display, round roughly according to the actual tolerance we 180 | # compare at. This is probably buggy as hell. 181 | n_round = abs(round(math.log(tolerance, 10))) 182 | 183 | try: 184 | # Allow to either have a single string for 'papersize' that is valid for *all* 185 | # PDFs, or a mapping of PDF stem names to their allowed sizes. This allows to 186 | # have mixed page sizes for multiple PDFs. 187 | size = size.get(Path(pdf.name).stem) 188 | except AttributeError: 189 | # Hopefully already a string 190 | pass 191 | 192 | target = Rect(*parse_papersize(size, unit=unit)) 193 | assert target.height >= target.width # Not a test, just correctness assertion 194 | 195 | for page in pdf: 196 | rect = page.CropBox # CropBox always sets rotation to 0 first 197 | 198 | # Convert width and height floats (unit pt) to string for papersize to parse. 199 | # This is a stupid move, but ensures we get nice output with the same units and 200 | # also that both dimension sets are sent through the parser, aka get the same 201 | # treatment. Any bugs in `papersize` would then cancel out. 202 | actual = Rect(*parse_papersize(f"{rect.width} {rect.height}", unit=unit)) 203 | assert actual.height >= actual.width # Not a test, just correctness assertion 204 | 205 | for dimension, t, f in zip(Rect._fields, target, actual): 206 | # Due to different ideas of what page sizes are exactly, compare with some 207 | # tolerance. Otherwise, the various floats would never compare equal. 208 | is_close = math.isclose(t, f, rel_tol=tolerance) 209 | msg = ( 210 | f"{dimension.capitalize()} mismatch (rel. tol.: {tolerance}):" 211 | + f" {round(f, n_round)}{unit} found, but" 212 | + f" {round(t, n_round)}{unit} requested." 213 | ) 214 | assert is_close, msg 215 | -------------------------------------------------------------------------------- /tests/tests/test_self.py: -------------------------------------------------------------------------------- 1 | from tests.utils import parse_size, fix_tzoffset, parse_duration 2 | from datetime import timedelta as td 3 | import pytest 4 | 5 | 6 | @pytest.mark.parametrize( 7 | ["size", "n"], 8 | [ 9 | ("0", 0), 10 | ("0.0000", 0), 11 | ("00000.0000", 0), 12 | (" 0 ", 0), 13 | (" 0 B", 0), 14 | ("0.1", 0), 15 | ("0.5", 0), 16 | ("0.0009K", 0), 17 | ("0.0009k", 0), 18 | ("0.009K", 9), 19 | ("1", 1), 20 | ("01", 1), 21 | ("1.0", 1), 22 | ("00022", 22), 23 | ("105", 105), 24 | ("106B", 106), 25 | ("0000106B", 106), 26 | ("769B", 769), 27 | ("12.234K", 12234), 28 | ("12.2349K", 12234), 29 | ("0.000009G", 9_000), 30 | ("497K", 497_000), 31 | ("0.3G", 300_000_000), 32 | ("554M", 554_000_000), 33 | ("155G", 155_000_000_000), 34 | ("664G", 664_000_000_000), 35 | ("864G", 864_000_000_000), 36 | ("155.3G", 155_300_000_000), 37 | ("853T", 853_000_000_000_000), 38 | ("999P", 999_000_000_000_000_000), 39 | ("100E", 100_000_000_000_000_000_000), 40 | # Case insensitive 41 | ("1b", 1), 42 | ("1k", 1_000), 43 | ("1m", 1_000_000), 44 | ("1g", 1_000_000_000), 45 | ("1t", 1_000_000_000_000), 46 | ("1p", 1_000_000_000_000_000), 47 | ("1e", 1_000_000_000_000_000_000), 48 | ], 49 | ) 50 | def test_parse_size(size, n): 51 | assert parse_size(size) == n 52 | 53 | 54 | @pytest.mark.parametrize( 55 | ["raw_date", "date"], 56 | [ 57 | # Unchanged: 58 | # No timezone info: 59 | ("D:20201103155304", "D:20201103155304"), 60 | # 61 | ("D:20201103155304+1000", "D:20201103155304+1000"), 62 | ("D:20201103155304-1000", "D:20201103155304-1000"), 63 | # Examples for %z from 64 | # https://docs.python.org/3/library/datetime.html#tzinfo-objects 65 | ("D:20201103155304+063415", "D:20201103155304+063415"), 66 | ("D:20201103155304+1030", "D:20201103155304+1030"), 67 | ("D:20201103155304-0400", "D:20201103155304-0400"), 68 | ("D:20201103155304-0000", "D:20201103155304-0000"), 69 | ("D:20201103155304+0000", "D:20201103155304+0000"), 70 | # Changed due to malformed tzinfo: 71 | ("D:20201103155304+01'00'", "D:20201103155304+0100"), 72 | ("D:20201103155304-01'00'", "D:20201103155304-0100"), 73 | ("D:20201103155304-11'11'", "D:20201103155304-1111"), 74 | ("D:20201103155304+10-10", "D:20201103155304+1010"), 75 | ("D:20201103155304+10-10.347289", "D:20201103155304+1010.347289"), 76 | ("D:20201103155304+01foifre00shfs", "D:20201103155304+0100"), 77 | ], 78 | ) 79 | def test_fix_tzoffset(raw_date, date): 80 | assert fix_tzoffset(raw_date) == date 81 | 82 | 83 | @pytest.mark.parametrize( 84 | ["raw_duration", "duration"], 85 | [ 86 | ("", None), 87 | (" ", None), 88 | ("Shouldnt match", None), 89 | ("???", None), 90 | # Since words start with the actual short letters (duh!), this works: 91 | ("1 day", td(days=1)), 92 | ("1 hour", td(hours=1)), 93 | ("1 minute", td(minutes=1)), 94 | ("1 second", td(seconds=1)), 95 | # But they cannot be combined: 96 | ("1 day 1 hour 1 minute 1 second", td(days=1)), 97 | ("10 hours 100 second", td(hours=10)), 98 | ("10 hours DOESNT MATTER", td(hours=10)), 99 | ("10 h DOESNT MATTER", td(hours=10)), 100 | # 101 | ("1 hour", td(hours=1)), 102 | ("1 minute", td(minutes=1)), 103 | ("1 second", td(seconds=1)), 104 | # It also means these work: 105 | ("1 durr", td(days=1)), 106 | ("1 hurr", td(hours=1)), 107 | ("1 mailbox", td(minutes=1)), 108 | ("1 sand", td(seconds=1)), 109 | # Zero 110 | ("0d", td(minutes=0, hours=0, days=0)), 111 | ("0h", td(minutes=0, hours=0, days=0)), 112 | ("0m", td(minutes=0, hours=0, days=0)), 113 | ("0d0m", td(minutes=0, hours=0, days=0)), 114 | ("0d0h", td(minutes=0, hours=0, days=0)), 115 | ("0m0h", td(minutes=0, hours=0, days=0)), 116 | ("0d0h0m", td(minutes=0, hours=0, days=0)), 117 | # Whitespace 118 | ("1d 1h 1m", td(minutes=1, hours=1, days=1)), 119 | (" 1d 1h 1m ", td(minutes=1, hours=1, days=1)), 120 | (" 1d 1h 1m ", td(minutes=1, hours=1, days=1)), 121 | ("\t1d\t1h\t1m", td(minutes=1, hours=1, days=1)), 122 | ("1d1h1m", td(minutes=1, hours=1, days=1)), 123 | # Negative 124 | ("-1d-1h-1m-1s", td(seconds=-1, minutes=-1, hours=-1, days=-1)), 125 | # We would write "1 day, 6 hours", but there is not limit: 126 | ("30h", td(hours=30)), 127 | ("300h", td(hours=300)), 128 | ("300m", td(minutes=300)), 129 | ("300s", td(seconds=300)), 130 | # 131 | ("-30h", td(hours=-30)), 132 | ("-300h", td(hours=-300)), 133 | ("-300m", td(minutes=-300)), 134 | ("-300s", td(seconds=-300)), 135 | # See: https://gist.github.com/santiagobasulto/698f0ff660968200f873a2f9d1c4113c#file-tests-py 136 | ("3d", td(days=3)), 137 | ("-3d", td(days=-3)), 138 | ("-37D", td(days=-37)), 139 | ("18h", td(hours=18)), 140 | ("-5h", td(hours=-5)), 141 | ("11H", td(hours=11)), 142 | ("129m", td(minutes=129)), 143 | ("-68m", td(minutes=-68)), 144 | ("12M", td(minutes=12)), 145 | ("3d5h", td(days=3, hours=5)), 146 | ("-3d-5h", td(days=-3, hours=-5)), 147 | ("13d4h19m", td(days=13, hours=4, minutes=19)), 148 | ("13d19m", td(days=13, minutes=19)), 149 | ("-13d-19m", td(days=-13, minutes=-19)), 150 | ("-13d19m", td(days=-13, minutes=19)), 151 | ("13d-19m", td(days=13, minutes=-19)), 152 | ("4h19m", td(hours=4, minutes=19)), 153 | ("-4h-19m", td(hours=-4, minutes=-19)), 154 | ("-4h19m", td(hours=-4, minutes=19)), 155 | ("4h-19m", td(hours=4, minutes=-19)), 156 | ], 157 | ) 158 | def test_parse_duration(raw_duration, duration): 159 | assert parse_duration(raw_duration) == duration 160 | -------------------------------------------------------------------------------- /tests/tests/utils.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | import logging 3 | import re 4 | import string 5 | from pathlib import Path 6 | 7 | _THIS_DIR = Path(__file__).parent 8 | 9 | # `resolve` gets rid of ".." representation, important for `relative_to` to work. 10 | _PROJECT_ROOT = (_THIS_DIR / ".." / "..").resolve() 11 | 12 | 13 | def parse_size(size: str) -> int: 14 | """Parses a string file size (e.g. "32G") into a bytes number. 15 | 16 | Works on the basis of 1000 steps, so not 1024. Probably wrong for that reason. 17 | 18 | Args: 19 | size: A human-readable file size, e.g. "32G", "10M". That is, without the "B" 20 | for "Bytes". 21 | 22 | Returns: 23 | Number of bytes for that file size. 24 | """ 25 | si_prefixes = ["B", "K", "M", "G", "T", "P", "E"] 26 | 27 | try: 28 | size = size.strip() 29 | except AttributeError: 30 | # Not a string, can't work with this, return this filth to the offender 31 | return size 32 | 33 | n = float(re.match(r"\d+(\.\d+)?", size).group()) 34 | for i, prefix in enumerate(si_prefixes): 35 | if re.search(prefix, size, re.IGNORECASE): 36 | factor = 10 ** (i * 3) 37 | break 38 | else: # nobreak 39 | logging.info(f"No unit prefix found in '{size}', interpreting as bytes.") 40 | factor = 1 41 | return int(factor * n) 42 | 43 | 44 | def fix_tzoffset(date: str) -> str: 45 | """Fixes malformed timezone info in a string, without parsing it further. 46 | 47 | The dates returned by `fitz.Document.metadata` have timezone information in the 48 | form "±HH'MM'", i.e. with extra apostrophes. These will be filtered out so that the 49 | resulting string can be parsed correctly by `datetime`'s `%z`, or automatically by 50 | `dateutil`. The latter fails for the malformed timezone returned by 51 | `fitz.Document.metadata`. 52 | 53 | The return of this function is designed to be fed into `dateutil.parser.parse`. 54 | 55 | Args: 56 | date: A date string to be parsed, with potentially malformed timezone 57 | information. 58 | 59 | Returns: 60 | Input date with all disallowed characters removed from the timezone info. 61 | """ 62 | 63 | def clean(match: re.Match) -> str: 64 | """Rebuilds match string to only contain allowed characters. 65 | 66 | See also: https://docs.python.org/3/library/re.html#re.sub 67 | """ 68 | allowed = string.digits + "." 69 | return "".join(char for char in match.group() if char in allowed) 70 | 71 | # Positive lookbehind: match only if *preceded* by that regex, however that regex 72 | # will not be part of the match. This allows us to clean just the timezone info 73 | # w/o having to deal w/ the ±. 74 | return re.sub(r"(?<=[+-]).+", clean, date) 75 | 76 | 77 | def parse_duration(duration: str) -> datetime.timedelta: 78 | """Parses a human-readable duration like "1d5h30m" 79 | 80 | Credit: https://gist.github.com/santiagobasulto/698f0ff660968200f873a2f9d1c4113c 81 | 82 | Args: 83 | duration: The human-readable string. 84 | 85 | Returns: 86 | A proper, parsed object to work with. 87 | """ 88 | duration = re.sub(r"\s+", "", duration) # Remove any whitespace 89 | pattern = re.compile( 90 | # Order here matters: 91 | r"((?P-?\d+)d)?" 92 | + r"((?P-?\d+)h)?" 93 | + r"((?P-?\d+)m)?" 94 | + r"((?P-?\d+)s)?", 95 | re.IGNORECASE | re.VERBOSE, 96 | ) 97 | match = pattern.match(duration) 98 | # Check if any match *content*, not just match object. All capture groups are 99 | # optional, so *any* string can match. See: 100 | # https://gist.github.com/santiagobasulto/698f0ff660968200f873a2f9d1c4113c#gistcomment-3518604 101 | if match.group(): 102 | parts = {k: int(v) for k, v in match.groupdict().items() if v} 103 | return datetime.timedelta(**parts) 104 | --------------------------------------------------------------------------------