From 077fd8fa3c3e3d552e15cb5c43d2e5f65b1c6b3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frank=20L=C3=B6ffler?= Date: Mon, 25 Aug 2025 08:51:10 +0200 Subject: [PATCH 01/17] add PLOS bst --- plos2025.bst | 1996 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1996 insertions(+) create mode 100644 plos2025.bst diff --git a/plos2025.bst b/plos2025.bst new file mode 100644 index 0000000..62a5b5e --- /dev/null +++ b/plos2025.bst @@ -0,0 +1,1996 @@ +%% The plos2025.bst file is intended for use in PLOS submissions. +%% It is a copy of the Vancouver BibTeX style (https://ctan.org/pkg/vancouver) +%% with "eprints", "doi", and "hyperref" enabled (see init.config.constants below). +%% +%% +%% This `vancouver.bst' bibliographic style file (for LaTeX/BibTeX) is +%% generated with the docstrip utility and modified manually to meet the +%% ``Uniform Requirements for Manuscripts Submitted to Biomedical Journals'' +%% as published in N Engl J Med 1997;336:309-315. +%% (also known as the Vancouver style) +%% The standards are summarized in: +%% https://www.nlm.nih.gov/bsd/uniform_requirements.html +%% and detailed in: +%% https://www.ncbi.nlm.nih.gov/books/NBK7256/ +%% +%%------------------------------------------------------------------- +%% +%% Author: Folkert van der Beek +%% Version: 1.0 +%% URL: https://gitlab.com/fvdbeek/vancouver.bst +%% +%% This work may be distributed and/or modified under the +%% conditions of the LaTeX Project Public License, either version 1.3 +%% of this license or (at your option) any later version. +%% The latest version of this license is in +%% http://www.latex-project.org/lppl.txt +%% and version 1.3 or later is part of all distributions of LaTeX +%% version 2005/12/01 or later. +%% +%%------------------------------------------------------------------- +%% +%% This bibliography style file is intended for texts in ENGLISH +%% This is a numerical citation style, and as such is standard LaTeX. +%% It requires no extra package to interface to the main text. +%% The form of the \bibitem entries is +%% \bibitem{key}... +%% Usage of \cite is as follows: +%% \cite{key} ==>> [#] +%% \cite[chap. 2]{key} ==>> [#, chap. 2] +%% where # is a number determined by the ordering in the reference list. +%% The order in the reference list is that by which the works were originally +%% cited in the text, or that in the database. + % +%% To change the reference numbering system from [1] to 1, +%% put the following code in the preamble: +%% \makeatletter % Reference list option change +%% \renewcommand\@biblabel[1]{#1} % from [1] to 1 +%% \makeatother % +%% +%%--------------------------------------------------------------------- + +%% List of all possible fields +ENTRY + { address + assignee % for patents + author + booktitle % for articles in books + chapter % for incollection, esp. internet documents + cartographer % for maps + day + edition + editor + howpublished + institution % for technical reports + inventor % for patents + journal + key + month + note + number + organization + pages + part + publisher + school + series + title + type + volume + word + year + eprint % urlbst + doi % urlbst + url % urlbst + lastchecked % urlbst + updated % urlbst + } + {} + { label } +%% Declaration of integer variables +INTEGERS { output.state before.all mid.sentence after.sentence after.block } +STRINGS { urlintro eprinturl eprintprefix doiprefix doiurl } % urlbst... +INTEGERS { hrefform addeprints adddoiresolver } +% Following constants may be adjusted by hand, if desired +FUNCTION {init.config.constants} +{ + "Available from: " 'urlintro := % prefix before URL + "http://arxiv.org/abs/" 'eprinturl := % prefix to make URL from eprint ref + "arXiv:" 'eprintprefix := % text prefix printed before eprint ref + "http://dx.doi.org/" 'doiurl := % prefix to make URL from DOI + "doi:" 'doiprefix := % text prefix printed before DOI ref + #1 'addeprints := % 0=no eprints; 1=include eprints + #1 'adddoiresolver := % 0=no DOI resolver; 1=include it + #2 'hrefform := % 0=no crossrefs; 1=hypertex xrefs; 2=hyperref refs +} +INTEGERS { + bracket.state + outside.brackets + open.brackets + within.brackets + close.brackets +} +% ...urlbst to here +FUNCTION {init.state.consts} +{ #0 'outside.brackets := % urlbst + #1 'open.brackets := + #2 'within.brackets := + #3 'close.brackets := + + #0 'before.all := + #1 'mid.sentence := + #2 'after.sentence := + #3 'after.block := +} +%% Declaration of string variables +STRINGS { s t} + +% urlbst +FUNCTION {output.nonnull.original} +{ 's := + output.state mid.sentence = + { ". " * write$ } + { output.state after.block = + { add.period$ write$ + newline$ + "\newblock " write$ + } + { output.state before.all = + 'write$ + { add.period$ " " * write$ } + if$ + } + if$ + mid.sentence 'output.state := + } + if$ + s +} + +% urlbst... +FUNCTION {output.nonnull} +{ % Save the thing we've been asked to output + 's := + % If the bracket-state is close.brackets, then add a close-bracket to + % what is currently at the top of the stack, and set bracket.state + % to outside.brackets + bracket.state close.brackets = + { "]" * + outside.brackets 'bracket.state := + } + 'skip$ + if$ + bracket.state outside.brackets = + { % We're outside all brackets -- this is the normal situation. + % Write out what's currently at the top of the stack, using the + % original output.nonnull function. + s + output.nonnull.original + } + { % Still in brackets. Add open-bracket or (continuation) comma, add the + % new text (in s) to the top of the stack, and move to the close-brackets + % state, ready for next time (unless inbrackets resets it). If we come + % into this branch, then output.state is carefully undisturbed. + bracket.state open.brackets = + { " [" * } + { ", " * } % bracket.state will be within.brackets + if$ + s * + close.brackets 'bracket.state := + } + if$ +} + +% Call this function just before adding something which should be presented in +% brackets. bracket.state is handled specially within output.nonnull. +FUNCTION {inbrackets} +{ bracket.state close.brackets = + { within.brackets 'bracket.state := } % reset the state: not open nor closed + { open.brackets 'bracket.state := } + if$ +} + +FUNCTION {format.lastchecked} +{ lastchecked empty$ + { "" } + { updated empty$ + { inbrackets "cited " lastchecked * } + { inbrackets "updated " updated * "; cited " * lastchecked * } + if$ + } + if$ +} +% ...urlbst to here + +FUNCTION {output} +{ duplicate$ empty$ + 'pop$ + 'output.nonnull + if$ +} + +FUNCTION {output.check} +{ 't := + duplicate$ empty$ + { pop$ "empty " t * " in " * cite$ * warning$ } + 'output.nonnull + if$ +} + +FUNCTION {fin.entry} +{ + bracket.state close.brackets = % urlbst + { "]" * } + 'skip$ + if$ + add.period$ + write$ + newline$ +} + +FUNCTION {new.block} +{ output.state before.all = + 'skip$ + { after.block 'output.state := } + if$ +} + +FUNCTION {new.sentence} +{ output.state after.block = + 'skip$ + { output.state before.all = + 'skip$ + { after.sentence 'output.state := } + if$ + } + if$ +} + +FUNCTION {add.blank} +{ " " * before.all 'output.state := +} + +FUNCTION {no.blank.or.punct} +{ "" * before.all 'output.state := +} + +FUNCTION {add.semicolon} +{ + ";" * + no.blank.or.punct +} + +FUNCTION {add.colon} +{ + ":" * + no.blank.or.punct +} + +FUNCTION {date.block} +{ + "." * + no.blank.or.punct +} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% LOGICAL `NOT', `AND', AND `OR' % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Logical 'not': +% If the first element on the stack is A then this function +% does the following: +% push { #0 } +% push { #1 } +% So now the first 3 elements of the stack are +% { #1 } { #0 } A +% The first 3 are popped and subjected to 'if': +% If A > 0 then { #0 } is executed, else { #1 } is executed: +% if A > 0 +% then 0 +% else 1 +% So consider integers as logicals, where 1 = true and 0 = false, +% then this does +% (if A then false else true) +% which is a logical 'not'. + +FUNCTION {not} +{ { #0 } + { #1 } + if$ +} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Logical 'and': +% If the first 2 elements on the stack are A B +% then this function does the following: +% push 'skip$ +% push { pop$ #0 } +% So now first 4 elements are +% { pop$ #0 } 'skip$ A B +% The first 3 are popped and subjected to 'if' (B is on top of +% the stack): +% If A > 0 then 'skip$ is executed, else { pop$ #0 } is executed: +% if A > 0 +% then (B stays on top of stack) +% else (B is popped and #0 is pushed) +% So consider integers as logicals, where 1 = true and 0 = false, +% then this does +% (if A then B else false) +% which is a logical 'and'. + +FUNCTION {and} +{ 'skip$ + { pop$ #0 } + if$ +} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Logical 'or': +% If the first 2 elements on the stack are A B +% then this function does the following: +% push { pop$ #1 } +% push 'skip$ +% So now first 4 elements are +% 'skip$ { pop$ #1 } A B +% The first 3 are popped and subjected to 'if' (B is on top of +% the stack): +% If A > 0 then { pop$ #1 } is executed, else 'skip$ is executed: +% if A > 0 +% then (B is popped and #1 is pushed) +% else (B stays on top of stack) +% So consider integers as logicals, where 1 = true and 0 = false, +% then this does +% (if A then true else B) +% which is a logical 'or'. + +FUNCTION {or} +{ { pop$ #1 } + 'skip$ + if$ +} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% GENERAL PURPOSE FUNCTIONS FOR FORMATTING % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% issues warning if field is empty +% call with +% "field" field warning.if.empty +% Note that the first field must be between quotes +% because it is the fieldname for use in the warning message. +% + +FUNCTION {warning.if.empty} +{ empty$ + { "No " swap$ * " in " * cite$ * warning$ } + { pop$ } + if$ +} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + % + % encloses string in pre- and postfix string + % call with + % prefix postfix S enclose.check + % delivers empty string if S empty + % +FUNCTION {enclose.check} +{ duplicate$ empty$ + { pop$ pop$ pop$ + "" + } + { swap$ * * } + if$ +} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% emphasizes top of stack +% call with +% string" emphasize.check +% + +FUNCTION {emphasize.check} +{ "\Bem{" swap$ + "}" swap$ + enclose.check +} + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + % + % brackets top of stack + % call with + % "string" bracket.check + % +FUNCTION {bracket.check} +{ "[" swap$ + "]" swap$ + enclose.check +} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + % + % parenthesizes top of stack + % call with + % "string" parenthesize + % +FUNCTION {parenthesize.check} +{ "(" swap$ + ")" swap$ + enclose.check +} + +STRINGS {z} + +FUNCTION {remove.dots} +{ 'z := % expects string on top of the stack, pops the string and assigns it to variable z + "" % push empty string + { z empty$ not } % returns 0 if variable z is empty + { z #1 #1 substring$ % push the first character of variable z + z #2 global.max$ substring$ 'z := % assigns the 2nd to last character of variable z to variable z + duplicate$ "\" = % pushes 1 if the last character is "\", otherwise 0 + { * % concatenates the last 2 literals + z #1 #1 substring$ % push the first character of variable z + z #2 global.max$ substring$ 'z := % assigns the 2nd to last character of variable z to variable z + * % concatenates the last 2 literals, i.e. every character, even a dot, following a "\" will be printed + } + { duplicate$ "." = % pushes 1 if the last character is ".", otherwise 0 + 'pop$ % pushes the pop$ function + { * } % concatenates the last 2 literals + if$ % pops the last character if it is a dot, otherwise concatenates it with the string on top of the stack + } + if$ + } + while$ +} + +INTEGERS {l} +FUNCTION{string.length} +{ + #1 'l := + { duplicate$ duplicate$ #1 l substring$ = not } + { l #1 + 'l := } + while$ + pop$ l +} + +STRINGS {replace find text} +INTEGERS {find_length} +FUNCTION {find.replace} +{ + 'replace := + 'find := + 'text := + find string.length 'find_length := + "" + { text empty$ not } + { text #1 find_length substring$ find = + { + replace * + text #1 find_length + global.max$ substring$ 'text := + } + { text #1 #1 substring$ * + text #2 global.max$ substring$ 'text := + } + if$ + } + while$ +} + +FUNCTION {new.block.checka} +{ empty$ + 'skip$ + 'new.block + if$ +} + +FUNCTION {new.block.checkb} +{ empty$ + swap$ empty$ + and + 'skip$ + 'new.block + if$ +} + +FUNCTION {new.sentence.checka} +{ empty$ + 'skip$ + 'new.sentence + if$ +} + +FUNCTION {new.sentence.checkb} +{ empty$ + swap$ empty$ + and + 'skip$ + 'new.sentence + if$ +} + +FUNCTION {field.or.null} +{ duplicate$ empty$ + { pop$ "" } + 'skip$ + if$ +} + +FUNCTION {emphasize} +{ skip$ } + +FUNCTION {tie.or.space.prefix} +{ duplicate$ text.length$ #3 < + { "~" } + { " " } + if$ + swap$ +} + +FUNCTION {capitalize} +{ "u" change.case$ "t" change.case$ } + +FUNCTION {space.word} +{ " " swap$ * " " * } + + % Here are the language-specific definitions for explicit words. + % Each function has a name bbl.xxx where xxx is the English word. + % The language selected here is ENGLISH + +FUNCTION {bbl.and} +{ "and"} + +FUNCTION {bbl.etal} +{ "et~al." } + +FUNCTION {bbl.editors} +{ "editors" } + +FUNCTION {bbl.editor} +{ "editor" } + +FUNCTION {bbl.cartographers} +{ "cartographers" } + +FUNCTION {bbl.cartographer} +{ "cartographer" } + +FUNCTION {bbl.inventors} +{ "inventors" } + +FUNCTION {bbl.inventor} +{ "inventor" } + +FUNCTION {bbl.assignees} +{ "assignees" } + +FUNCTION {bbl.assignee} +{ "assignee" } + +FUNCTION {bbl.edby} +{ "edited by" } + +FUNCTION {bbl.edition} +{ "ed." } + +FUNCTION {bbl.volume} +{ "vol." } + +FUNCTION {bbl.of} +{ "of" } + +FUNCTION {bbl.number} +{ "no." } + +FUNCTION {bbl.nr} +{ "no." } + +FUNCTION {bbl.in} +{ "in" } + +FUNCTION {bbl.pages} +{ "p." } + +FUNCTION {bbl.page} +{ "p." } + +FUNCTION {bbl.chapter} +{ "chap." } + +FUNCTION {bbl.techrep} +{ "Tech. Rep." } + +FUNCTION {bbl.mthesis} +{ "Master's thesis" } + +FUNCTION {bbl.phdthesis} +{ "Ph.D. thesis" } + +FUNCTION {bbl.first} +{ "1st" } + +FUNCTION {bbl.second} +{ "2nd" } + +FUNCTION {bbl.third} +{ "3rd" } + +FUNCTION {bbl.fourth} +{ "4th" } + +FUNCTION {bbl.fifth} +{ "5th" } + +FUNCTION {bbl.st} +{ "st" } + +FUNCTION {bbl.nd} +{ "nd" } + +FUNCTION {bbl.rd} +{ "rd" } + +FUNCTION {bbl.th} +{ "th" } + +MACRO {jan} {"Jan."} + +MACRO {feb} {"Feb."} + +MACRO {mar} {"Mar."} + +MACRO {apr} {"Apr."} + +MACRO {may} {"May"} + +MACRO {jun} {"Jun."} + +MACRO {jul} {"Jul."} + +MACRO {aug} {"Aug."} + +MACRO {sep} {"Sep."} + +MACRO {oct} {"Oct."} + +MACRO {nov} {"Nov."} + +MACRO {dec} {"Dec."} + +FUNCTION {eng.ord} +{ duplicate$ "1" swap$ * + #-2 #1 substring$ "1" = + { bbl.th * } + { duplicate$ #-1 #1 substring$ + duplicate$ "1" = + { pop$ bbl.st * } + { duplicate$ "2" = + { pop$ bbl.nd * } + { "3" = + { bbl.rd * } + { bbl.th * } + if$ + } + if$ + } + if$ + } + if$ +} + +FUNCTION {bibinfo.check} +{ swap$ + duplicate$ missing$ + { + pop$ pop$ + "" + } + { duplicate$ empty$ + { + swap$ pop$ + } + { swap$ + pop$ + } + if$ + } + if$ +} + +FUNCTION {bibinfo.warn} +{ swap$ + duplicate$ missing$ + { + swap$ "missing " swap$ * " in " * cite$ * warning$ pop$ + "" + } + { duplicate$ empty$ + { + swap$ "empty " swap$ * " in " * cite$ * warning$ + } + { swap$ + pop$ + } + if$ + } + if$ +} + +STRINGS { bibinfo} +INTEGERS { nameptr namesleft numnames } + +FUNCTION {format.names} +{ 'bibinfo := + duplicate$ empty$ 'skip$ { + "." ". " find.replace 's := + "" 't := + #1 'nameptr := + s num.names$ 'numnames := + numnames 'namesleft := + { namesleft #0 > } + { s nameptr + "{vv~}{ll}{ f{}}{ jj}" + format.name$ + remove.dots + bibinfo bibinfo.check + 't := + nameptr #1 > + { + nameptr #6 + #1 + = + numnames #6 + > and + { "others" 't := + #1 'namesleft := } + 'skip$ + if$ + namesleft #1 > + { ", " * t * } + { + "," * + s nameptr "{ll}" format.name$ duplicate$ "others" = + { 't := } + { pop$ } + if$ + t "others" = + { + " " * bbl.etal * + } + { " " * t * } + if$ + } + if$ + } + 't + if$ + nameptr #1 + 'nameptr := + namesleft #1 - 'namesleft := + } + while$ + } if$ +} + +FUNCTION {format.names.org} +{ 'bibinfo := + duplicate$ empty$ 'skip$ { + 's := + "" 't := + #1 'nameptr := + s num.names$ 'numnames := + numnames 'namesleft := + { namesleft #0 > } + { s nameptr + "{ff~}{vv~}{ll}" + format.name$ + bibinfo bibinfo.check + 't := + nameptr #1 > + { + namesleft #1 > + { "; " * t * } + { + ";" * + s nameptr "{ll}" format.name$ duplicate$ "others" = + { 't := } + { pop$ } + if$ + t "others" = + { + " " * bbl.etal * + } + { " " * t * } + if$ + } + if$ + } + 't + if$ + nameptr #1 + 'nameptr := + namesleft #1 - 'namesleft := + } + while$ + } if$ +} + +FUNCTION {format.names.ed} +{ + format.names +} + +FUNCTION {format.authors} +{ + author "author" format.names + %%"." " " "author" find.replace format.names +} + +FUNCTION {format.organizations} +{ organization "organization" format.names.org +} + +FUNCTION {get.bbl.editor} +{ editor num.names$ #1 > 'bbl.editors 'bbl.editor if$ } + +FUNCTION {get.bbl.cartographer} +{ cartographer num.names$ #1 > 'bbl.cartographers 'bbl.cartographer if$ } + +FUNCTION {get.bbl.inventor} +{ inventor num.names$ #1 > 'bbl.inventors 'bbl.inventor if$ } + +FUNCTION {get.bbl.assignee} +{ assignee num.names$ #1 > 'bbl.assignees 'bbl.assignee if$ } + +FUNCTION {format.editors} +{ editor "editor" format.names duplicate$ empty$ 'skip$ + { + "," * + " " * + get.bbl.editor + * + } + if$ +} + +FUNCTION {format.assignees} +{ assignee "assignee" format.names.org duplicate$ empty$ 'skip$ + { + "," * + " " * + get.bbl.assignee + * + } + if$ +} + +FUNCTION {format.cartographers} +{ cartographer "cartographer" format.names duplicate$ empty$ 'skip$ + { + "," * + " " * + get.bbl.cartographer + * + } + if$ +} + +FUNCTION {format.inventors} +{ inventor "inventor" format.names duplicate$ empty$ 'skip$ + { + "," * + " " * + get.bbl.inventor + * + } + if$ +} + +FUNCTION {format.note} +{ + note empty$ + { "" } + { note #1 #1 substring$ + duplicate$ "{" = + 'skip$ + { output.state mid.sentence = + { "l" } + { "u" } + if$ + change.case$ + } + if$ + note #2 global.max$ substring$ * "note" bibinfo.check + } + if$ +} + +FUNCTION {format.title} +{ title +%%duplicate$ empty$ 'skip$ +%% { "t" change.case$ } +%%if$ + "title" bibinfo.check +} + +FUNCTION {format.type} +{ type empty$ + 'skip$ + { inbrackets type } + %%{ add.blank "[" type * "]" * } + if$ +} + +FUNCTION {output.bibitem} +{ outside.brackets 'bracket.state := % urlbst + newline$ + "\bibitem{" write$ + cite$ write$ + "}" write$ + newline$ + "" + before.all 'output.state := +} + +FUNCTION {hyphenate} +{ 't := + "" + { t empty$ not } + { t #1 #1 substring$ "-" = + { "-" * + { t #1 #1 substring$ "-" = } + { t #2 global.max$ substring$ 't := } + while$ + } + { t #1 #1 substring$ * + t #2 global.max$ substring$ 't := + } + if$ + } + while$ +} + +FUNCTION {word.in} +{ bbl.in capitalize + ":" * + " " * } + +FUNCTION {format.journal.date} +{ + month "month" bibinfo.check + duplicate$ empty$ + year "year" bibinfo.check duplicate$ empty$ + { + swap$ 'skip$ + { "there's a month but no year in " cite$ * warning$ } + if$ + * + } + { swap$ 'skip$ + { + " " * swap$ + } + if$ + * + remove.dots + } + if$ + duplicate$ empty$ + 'skip$ + { + before.all 'output.state := + after.sentence 'output.state := + } + if$ +} + +FUNCTION {format.date} +{ + no.blank.or.punct + ";" + duplicate$ empty$ + year "year" bibinfo.check duplicate$ empty$ + { swap$ 'skip$ + { "there's a month but no year in " cite$ * warning$ } + if$ + * + } + { swap$ 'skip$ + { + swap$ + " " * swap$ + } + if$ + * + } + if$ +} + +FUNCTION {format.btitle} +{ title "title" bibinfo.check + duplicate$ empty$ 'skip$ + { + } + if$ +} + +FUNCTION {either.or.check} +{ empty$ + 'pop$ + { "can't use both " swap$ * " fields in " * cite$ * warning$ } + if$ +} + +FUNCTION {format.bvolume} +{ volume empty$ + { "" } + { bbl.volume volume tie.or.space.prefix + "volume" bibinfo.check * * + series "series" bibinfo.check + duplicate$ empty$ 'pop$ + { swap$ bbl.of space.word * swap$ + emphasize * } + if$ + "volume and number" number either.or.check + } + if$ +} + +FUNCTION {format.number.series} +{ volume empty$ + { number empty$ + { series field.or.null } + { series empty$ + { number "number" bibinfo.check } + { output.state mid.sentence = + { bbl.number } + { bbl.number capitalize } + if$ + number tie.or.space.prefix "number" bibinfo.check * * + bbl.in space.word * + series "series" bibinfo.check * + } + if$ + } + if$ + } + { "" } + if$ +} + +FUNCTION {is.num} +{ chr.to.int$ + duplicate$ "0" chr.to.int$ < not + swap$ "9" chr.to.int$ > not and +} + +FUNCTION {extract.num} +{ duplicate$ 't := + "" 's := + { t empty$ not } + { t #1 #1 substring$ + t #2 global.max$ substring$ 't := + duplicate$ is.num + { s swap$ * 's := } + { pop$ "" 't := } + if$ + } + while$ + s empty$ + 'skip$ + { pop$ s } + if$ +} + +FUNCTION {convert.edition} +{ extract.num "l" change.case$ 's := + s "first" = s "1" = or + { bbl.first 't := } + { s "second" = s "2" = or + { bbl.second 't := } + { s "third" = s "3" = or + { bbl.third 't := } + { s "fourth" = s "4" = or + { bbl.fourth 't := } + { s "fifth" = s "5" = or + { bbl.fifth 't := } + { s #1 #1 substring$ is.num + { s eng.ord 't := } + { edition 't := } + if$ + } + if$ + } + if$ + } + if$ + } + if$ + } + if$ + t +} + +FUNCTION {format.edition} +{ edition duplicate$ empty$ 'skip$ + { + convert.edition + output.state mid.sentence = + { "l" } + { "t" } + if$ change.case$ + "edition" bibinfo.check + " " * bbl.edition * + } + if$ +} +INTEGERS { multiresult } +FUNCTION {multi.page.check} +{ 't := + #0 'multiresult := + { multiresult not + t empty$ not + and + } + { t #1 #1 substring$ + duplicate$ "-" = + swap$ duplicate$ "," = + swap$ "+" = + or or + { #1 'multiresult := } + { t #2 global.max$ substring$ 't := } + if$ + } + while$ + multiresult +} + +FUNCTION {is.letter} +{ duplicate$ empty$ + { pop$ #0 } + { chr.to.int$ + duplicate$ "A" chr.to.int$ < + { pop$ #0 } + { duplicate$ "Z" chr.to.int$ > + { duplicate$ "a" chr.to.int$ < + { pop$ #0 } + { duplicate$ "z" chr.to.int$ > + { pop$ #0 } + { pop$ #1 } + if$ + } + if$ + } + { pop$ #1 } + if$ + } + if$ + } + if$ +} + +FUNCTION {is.digit} +{ duplicate$ empty$ + { pop$ #0 } + { chr.to.int$ + duplicate$ "0" chr.to.int$ < + { pop$ #0 } + { "9" chr.to.int$ > + { #0 } + { #1 } + if$ + } + if$ + } + if$ +} + +FUNCTION {is.letter.digit} +{ duplicate$ is.letter + swap$ is.digit or +} + +INTEGERS { charptr len } + +STRINGS { start.number end.number range.separator } + +FUNCTION {abbreviate.range.numbers} +{ end.number end.number text.length$ #1 substring$ is.letter + { start.number range.separator * end.number * } + { end.number text.length$ 'len := + start.number text.length$ len < + 'skip$ + { start.number text.length$ len - #1 + 'charptr := + { end.number text.length$ #1 > + start.number charptr #1 substring$ + end.number #1 #1 substring$ = and + } + { charptr #1 + 'charptr := + end.number #2 global.max$ substring$ 'end.number := + } + while$ + } + if$ + start.number range.separator * end.number * + } + if$ +} + +% This a helper function for use in format.page.numbers +FUNCTION {append.pages.part} +{ duplicate$ duplicate$ text.length$ #1 substring$ "," = + { " " * } + 'skip$ + if$ + end.number empty$ + { start.number empty$ + 'skip$ + { start.number * } + if$ + } + { abbreviate.range.numbers * } + if$ + "" 'start.number := + "" 'end.number := + "" 'range.separator := +} + +FUNCTION {format.page.numbers} +{ 's := + "" 't := + "" 'start.number := + "" 'end.number := + "" 'range.separator := + "" + { s empty$ not } + { s #1 #1 substring$ 't := + t is.letter.digit + { range.separator empty$ + { start.number t * 'start.number := } + { end.number t * 'end.number := } + if$ + } + { s #1 #2 substring$ "--" = + { "--" 'range.separator := } + { t "-" = + { "-" 'range.separator := } + { append.pages.part + t * + } + if$ + } + if$ + } + if$ + s #2 global.max$ substring$ 's := + } + while$ + append.pages.part +} + +FUNCTION {format.pages} +{ pages duplicate$ empty$ 'skip$ + { duplicate$ multi.page.check + { + format.page.numbers + bbl.pages swap$ + hyphenate + } + { + bbl.page swap$ + } + if$ + tie.or.space.prefix + "pages" bibinfo.check + * * + } + if$ +} + +FUNCTION {format.journal.pages} +{ pages empty$ 'skip$ + { add.colon } + if$ + pages duplicate$ empty$ 'pop$ + { + format.page.numbers + hyphenate + "pages" bibinfo.check + * + } + if$ +} + +FUNCTION {format.vol.num} +{ volume field.or.null + duplicate$ empty$ 'skip$ + { + "volume" bibinfo.check + } + if$ + number "number" bibinfo.check duplicate$ empty$ 'skip$ + { + swap$ duplicate$ empty$ + { "there's a number but no volume in " cite$ * warning$ } + 'skip$ + if$ + swap$ + "(" swap$ * ")" * + } + if$ * +} + +FUNCTION {format.vol.num.pages} +{ volume empty$ number empty$ and + 'skip$ + { add.semicolon } + if$ + volume field.or.null + duplicate$ empty$ 'skip$ + { + "volume" bibinfo.check + } + if$ + number "number" bibinfo.check duplicate$ empty$ 'skip$ + { + swap$ duplicate$ empty$ + { "there's a number but no volume in " cite$ * warning$ } + 'skip$ + if$ + swap$ + "(" swap$ * ")" * + } + if$ * + format.journal.pages +} + +FUNCTION {format.chapter.pages} +{ chapter empty$ + 'format.pages + { type empty$ + { bbl.chapter } + { type "l" change.case$ + "type" bibinfo.check + } + if$ + chapter tie.or.space.prefix + "chapter" bibinfo.check + * * + pages empty$ + 'skip$ + { ", " * format.pages * } + if$ + } + if$ + } + + FUNCTION {format.booktitle} + { + booktitle "booktitle" bibinfo.check + } + + FUNCTION {format.in.ed.booktitle} + { format.booktitle duplicate$ empty$ 'skip$ + { + editor "editor" format.names.ed duplicate$ empty$ 'pop$ + { + "," * + " " * + get.bbl.editor + ". " * + * swap$ + * } + if$ + word.in swap$ * + } + if$ + } + + FUNCTION {format.in.ed.title} + { format.title duplicate$ empty$ 'skip$ + { + editor "editor" format.names.ed duplicate$ empty$ 'pop$ + { + "," * + " " * + get.bbl.editor + ". " * + * swap$ + * } + if$ + word.in swap$ * + } + if$ + } + + FUNCTION {empty.misc.check} + { author empty$ title empty$ howpublished empty$ + month empty$ year empty$ note empty$ + and and and and and + { "all relevant fields are empty in " cite$ * warning$ } + 'skip$ + if$ + } + FUNCTION {format.thesis.type} + { type duplicate$ empty$ + 'pop$ + { swap$ pop$ + "t" change.case$ "type" bibinfo.check + } + if$ +} +FUNCTION {format.tr.number} +{ + number "number" bibinfo.check + %%type duplicate$ empty$ + %%{ pop$ bbl.techrep } + %%'skip$ + %%if$ + %%"type" bibinfo.check + %%swap$ duplicate$ empty$ + %%{ pop$ "t" change.case$ } + %%{ tie.or.space.prefix * * } + %%if$ +} + +FUNCTION {format.org.or.pub} +{ 't := + "" + address empty$ t empty$ and + 'skip$ + { + address "address" bibinfo.check * + t empty$ + 'skip$ + { address empty$ + 'skip$ + { ": " * } + if$ + t * + } + if$ + } + if$ +} + +FUNCTION {format.publisher.address} +{ publisher "publisher" bibinfo.warn format.org.or.pub +} + +FUNCTION {format.organization.address} +{ organization "organization" bibinfo.check format.org.or.pub +} + +FUNCTION {format.institution.address} +{ institution "institution" bibinfo.check format.org.or.pub +} + +FUNCTION {format.school.address} +{ school "school" bibinfo.check format.org.or.pub +} + + +% urlbst... +% Functions for making hypertext links. +% In all cases, the stack has (link-text href-url) +% +% make 'null' specials +FUNCTION {make.href.null} +{ + pop$ +} +% make hypertex specials +FUNCTION {make.href.hypertex} +{ + "\special {html: }" * swap$ * + "\special {html:}" * +} +% make hyperref specials +FUNCTION {make.href.hyperref} +{ + "\href {" swap$ * "} {" * swap$ * "}" * +} +FUNCTION {make.href} +{ hrefform #2 = + 'make.href.hyperref % hrefform = 2 + { hrefform #1 = + 'make.href.hypertex % hrefform = 1 + 'make.href.null % hrefform = 0 (or anything else) + if$ + } + if$ +} + +FUNCTION {format.url} +{ url empty$ + { "" } + { hrefform #1 = + { % special case -- add HyperTeX specials + urlintro "\url{" url * "}" * url make.href.hypertex * } + { urlintro "\url{" * url * "}" * } + if$ + } + if$ +} + +FUNCTION {format.eprint} +{ eprint empty$ + { "" } + { eprintprefix eprint * eprinturl eprint * make.href } + if$ +} + +FUNCTION {format.doi} +{ doi empty$ + { "" } + { doiprefix doi * doiurl doi * make.href } + if$ +} + +% Output a URL. We can't use the more normal idiom (something like +% `format.url output'), because the `inbrackets' within +% format.lastchecked applies to everything between calls to `output', +% so that `format.url format.lastchecked * output' ends up with both +% the URL and the lastchecked in brackets. +FUNCTION {output.url} +{ url empty$ + 'skip$ + { new.block + format.url output + format.lastchecked output + } + if$ +} + +FUNCTION {output.web.refs} +{ + new.block + output.url + addeprints eprint empty$ not and + { format.eprint output.nonnull } + 'skip$ + if$ + adddoiresolver doi empty$ not and + { format.doi output.nonnull } + 'skip$ + if$ +% addeprints +% { eprint empty$ +% 'skip$ +% { format.eprint output.nonnull } +% if$ +% } +% 'skip$ +% if$ +} + +% Webpage entry type. +% Title and url fields required; +% author, note, year, month, and lastchecked fields optional +STRINGS {database} +FUNCTION {webpage} +{ output.bibitem + author empty$ + { editor empty$ + 'skip$ % author and editor both optional + { format.editors output.nonnull } + if$ + } + { editor empty$ + { format.authors output.nonnull } + { "can't use both author and editor fields in " cite$ * warning$ } + if$ + } + if$ +% author empty$ +% 'skip$ +% { format.authors output.nonnull } +% if$ + new.block + format.title "title" output.check + journal empty$ + { + format.type "type" output.check + publisher empty$ + 'skip$ + { format.publisher.address output } + if$ + "database on the Internet" 'database := + type database = + { format.journal.date "year" output.check } + { format.date "year" output.check } + if$ + lastchecked empty$ + 'skip$ + { format.lastchecked output } + if$ + new.block + part empty$ + 'skip$ + { part output } + if$ + pages empty$ + 'skip$ + { pages bracket.check output } + if$ + } + { journal + remove.dots + "journal" bibinfo.check + "journal" output.check + format.type "type" output.check + format.journal.date "year" output.check + lastchecked empty$ + 'skip$ + { format.lastchecked output + ";" no.blank.or.punct output + } + if$ + no.blank.or.punct format.vol.num output + pages empty$ + 'skip$ + { ":" no.blank.or.punct output + no.blank.or.punct pages bracket.check output + } + if$ + new.block + } + if$ + format.url "url" output.check + new.block + note output + fin.entry +} +% ...urlbst to here + +FUNCTION {misc} +{ output.bibitem + format.authors "author" output.check + format.editors "author and editor" output.check + format.title "title" output.check + type missing$ + { skip$ } + { format.type "type" output.check } + %%{ inbrackets type output } + if$ + format.publisher.address output + format.date "year" output.check + new.block + format.note output + new.block + howpublished new.block.checka + howpublished "howpublished" bibinfo.check output + output.web.refs % urlbst + fin.entry + empty.misc.check +} + +FUNCTION {article} +{ output.bibitem + format.authors "author" output.check + organization empty$ + 'skip$ + { author empty$ + { + format.organizations "organization" output.check + } + { + "; " * + no.blank.or.punct + format.organizations "organization" output.check + } + if$ + } + if$ + new.block + format.title "title" output.check + type missing$ + { skip$ } + { format.type "type" output.check } + if$ + new.block + journal + remove.dots + "journal" bibinfo.check + "journal" output.check + format.journal.date "year" output.check + format.vol.num.pages output + new.block + format.note output + output.web.refs % urlbst + fin.entry +} + +FUNCTION {book} +{ output.bibitem + author empty$ + { editor empty$ + { format.organizations "organization" output.check } + { format.editors "author and editor" output.check } + if$ + } + { format.authors output.nonnull + "author and editor" editor either.or.check + } + if$ + new.block + format.btitle "title" output.check + format.bvolume output + new.block + format.edition output + new.sentence + author empty$ not + editor empty$ not + and + { format.editors "author and editor" output.check } + 'skip$ + if$ + format.number.series output + format.publisher.address output + format.date "year" output.check + new.block + format.note output + output.web.refs % urlbst + fin.entry +} + +FUNCTION {booklet} +{ misc } + +FUNCTION {dictionary} +{ output.bibitem + format.booktitle "booktitle" output.check + format.bvolume output + new.block + format.edition output + new.sentence + format.publisher.address output + format.date "year" output.check + format.btitle "title" output.check + add.semicolon + add.blank + format.pages "pages" output.check + new.block + format.note output + output.web.refs % urlbst + fin.entry +} + +FUNCTION {inbook} +{ output.bibitem + format.authors "author" output.check + new.block + chapter "chapter" output.check + new.block + format.in.ed.title "title" output.check + format.bvolume output + format.edition output + new.sentence + format.number.series output + format.publisher.address output + format.date "year" output.check + date.block + add.blank + format.pages "pages" output.check + new.block + format.note output + output.web.refs % urlbst + fin.entry +} + +FUNCTION {incollection} +{ output.bibitem + format.authors "author" output.check + new.block + format.title "title" output.check + new.block + format.in.ed.booktitle "booktitle" output.check + format.bvolume output + format.edition output + new.sentence + format.number.series output + format.publisher.address output + format.date "year" output.check + date.block + add.blank + format.pages "pages" output.check + new.block + format.note output + output.web.refs % urlbst + fin.entry +} + +FUNCTION {inproceedings} +{ output.bibitem + format.authors "author" output.check + new.block + format.title "title" output.check + new.block + format.in.ed.booktitle "booktitle" output.check + format.bvolume output + new.sentence + format.number.series output + publisher empty$ + { format.organization.address output } + { organization "organization" bibinfo.check output + format.publisher.address output + } + if$ + format.date "year" output.check + date.block + add.blank + format.pages "pages" output.check + new.block + format.note output + output.web.refs % urlbst + fin.entry +} + +FUNCTION {conference} +{inproceedings} + +FUNCTION {manual} +{misc} + +FUNCTION {phdthesis} +{ output.bibitem + format.authors "author" output.check + new.block + format.btitle + "title" output.check + format.type "type" output.check + new.block + format.school.address output + format.date "year" output.check + new.block + format.note output + output.web.refs % urlbst + fin.entry +} + +FUNCTION {mastersthesis} +{phdthesis} + +FUNCTION {proceedings} +{ output.bibitem + editor empty$ + { organization "organization" bibinfo.check output + } + { format.editors output.nonnull } + if$ + new.block + format.btitle "title" output.check + format.bvolume output + editor empty$ + { publisher empty$ + 'skip$ + { + new.sentence + format.number.series output + format.publisher.address output + } + if$ + } + { publisher empty$ + { + new.sentence + format.organization.address output } + { + new.sentence + organization "organization" bibinfo.check output + format.publisher.address output + } + if$ + } + if$ + format.date "year" output.check + new.block + format.note output + output.web.refs % urlbst + fin.entry +} + +FUNCTION {techreport} +{ output.bibitem + format.authors "author" output.check + new.block + format.title + "title" output.check + new.block + format.institution.address output + format.date "year" output.check + format.tr.number output.nonnull + new.block + format.note output + output.web.refs % urlbst + fin.entry +} + +FUNCTION {map} +{ output.bibitem + format.cartographers "cartographer" output.check + new.block + format.title + "title" output.check + format.type "type" output.check + new.block + format.publisher.address output + format.date "year" output.check + new.block + format.note output + output.web.refs % urlbst + fin.entry +} + +FUNCTION {patent} +{ output.bibitem + format.inventors "inventor" output.check + "; " * + no.blank.or.punct + format.assignees "assignee" output.check + new.block + format.title + "title" output.check + new.block + format.tr.number output.nonnull + format.date "year" output.check + new.block + format.note output + output.web.refs % urlbst + fin.entry +} + +FUNCTION {unpublished} +{ output.bibitem + format.authors "author" output.check + new.block + format.title "title" output.check + format.date output + new.block + format.note "note" output.check + output.web.refs % urlbst + fin.entry +} + +FUNCTION {default.type} { misc } +READ +STRINGS { longest.label } +INTEGERS { number.label longest.label.width } +FUNCTION {initialize.longest.label} +{ "" 'longest.label := + #1 'number.label := + #0 'longest.label.width := +} +FUNCTION {longest.label.pass} +{ number.label int.to.str$ 'label := + number.label #1 + 'number.label := + label width$ longest.label.width > + { label 'longest.label := + label width$ 'longest.label.width := + } + 'skip$ + if$ +} +EXECUTE {initialize.longest.label} +ITERATE {longest.label.pass} +FUNCTION {begin.bib} +{ preamble$ empty$ + 'skip$ + { preamble$ write$ newline$ } + if$ + "\begin{thebibliography}{" longest.label * "}" * + write$ newline$ +} +EXECUTE {begin.bib} +EXECUTE {init.config.constants} +EXECUTE {init.state.consts} +ITERATE {call.type$} +FUNCTION {end.bib} +{ newline$ + "\end{thebibliography}" write$ newline$ +} +EXECUTE {end.bib} +%% End of customized bst file +%% +%% End of file `plos2025.bst'. From 15b0d6af0367e78ee20014276612d62c7a271005 Mon Sep 17 00:00:00 2001 From: Magnus Hagdorn Date: Mon, 25 Aug 2025 09:49:05 +0200 Subject: [PATCH 02/17] reformat and keep flake8 happy --- contributors.py | 73 +++++++++++++++++++++++++++++-------------------- 1 file changed, 43 insertions(+), 30 deletions(-) diff --git a/contributors.py b/contributors.py index 356fcd5..20eb834 100755 --- a/contributors.py +++ b/contributors.py @@ -4,33 +4,46 @@ import yaml -with open("contributors.yml") as f: - data = yaml.safe_load(f) - -# Sort by last name and contribution tier -data["authors"] = list(sorted(sorted(data["authors"], key=lambda x: x["lastName"]), key=lambda x: x.get("tier", 2))) - -# Ensure that we have unique indices for the affiliations -affiliations = list() -for author in data["authors"]: - if 'affiliations' in author: - affiliations.extend(author["affiliations"]) -# make sure affiliations are not duplicated - here by checking for exact name string -affiliations = list({aff['name']: aff for aff in affiliations}.values()) - -# create and add unique index and also a reverse lookup table -data["affiliations"] = {i + 1: aff for i, aff in enumerate(affiliations)} -aff_index_by_name = {aff['name']: i for i, aff in data["affiliations"].items()} - -# attach index to authors -for author in data["authors"]: - if 'affiliations' in author: - author["affiliations"] = [aff_index_by_name[aff['name']] for aff in author["affiliations"]] - -env = jinja2.Environment( - loader=jinja2.FileSystemLoader(os.getcwd()), - keep_trailing_newline=True, -) - -with open("./contributors.tex", "w") as out: - out.write(env.get_template("contributors.tex.j2").render(data=data)) +def main(): + + with open("contributors.yml") as f: + data = yaml.safe_load(f) + + # Sort by last name and contribution tier + data["authors"] = list( + sorted( + sorted(data["authors"], key=lambda x: x["lastName"]), + key=lambda x: x.get("tier", 2))) + + # Ensure that we have unique indices for the affiliations + affiliations = [] + for author in data["authors"]: + if 'affiliations' in author: + affiliations.extend(author["affiliations"]) + # make sure affiliations are not duplicated - here by checking + # for exact name string + affiliations = list({aff['name']: aff for aff in affiliations}.values()) + + # create and add unique index and also a reverse lookup table + data["affiliations"] = {i + 1: aff for i, aff in enumerate(affiliations)} + aff_index_by_name = { + aff['name']: i for i, aff in data["affiliations"].items()} + + # attach index to authors + for author in data["authors"]: + if 'affiliations' in author: + author["affiliations"] = [ + aff_index_by_name[ + aff['name']] for aff in author["affiliations"]] + + env = jinja2.Environment( + loader=jinja2.FileSystemLoader(os.getcwd()), + keep_trailing_newline=True, + ) + + with open("./contributors.tex", "w") as out: + out.write(env.get_template("contributors.tex.j2").render(data=data)) + + +if __name__ == '__main__': + main() From 7303b08242ce637e1d07c80a2b83a7c68717bec2 Mon Sep 17 00:00:00 2001 From: Magnus Hagdorn Date: Mon, 25 Aug 2025 10:00:36 +0200 Subject: [PATCH 03/17] use argument parser --- Makefile | 4 ++-- contributors.py | 19 ++++++++++++++++--- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index 86d92d0..5feb3d3 100644 --- a/Makefile +++ b/Makefile @@ -7,8 +7,8 @@ clean: paper.pdf: paper.tex positionpaper.bib contributors.tex latexmk -pdflatex paper.tex -contributors.tex: contributors.tex.j2 contributors.yml - python3 contributors.py +contributors.tex: contributors.yml contributors.tex.j2 + python3 contributors.py $< -o $@ plots:: $(MAKE) -C group_composition_plot diff --git a/contributors.py b/contributors.py index 20eb834..8e96f5b 100755 --- a/contributors.py +++ b/contributors.py @@ -2,11 +2,20 @@ import jinja2 import os import yaml +import argparse +from pathlib import Path def main(): - with open("contributors.yml") as f: + parser = argparse.ArgumentParser() + parser.add_argument("contributors", type=Path, + help="yml file containing the contributors") + parser.add_argument("-o", "--output", type=Path, + help="the name of the output file") + args = parser.parse_args() + + with args.contributors.open('r') as f: data = yaml.safe_load(f) # Sort by last name and contribution tier @@ -41,8 +50,12 @@ def main(): keep_trailing_newline=True, ) - with open("./contributors.tex", "w") as out: - out.write(env.get_template("contributors.tex.j2").render(data=data)) + contribs = env.get_template("contributors.tex.j2").render(data=data) + + if args.output is not None: + args.output.write_text(contribs) + else: + print(contribs) if __name__ == '__main__': From d13a3c326ed8d9eb16509803a0c4ea6278d2768b Mon Sep 17 00:00:00 2001 From: Magnus Hagdorn Date: Mon, 25 Aug 2025 10:03:56 +0200 Subject: [PATCH 04/17] specify template on command line --- Makefile | 2 +- contributors.py | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 5feb3d3..a78af30 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,7 @@ paper.pdf: paper.tex positionpaper.bib contributors.tex latexmk -pdflatex paper.tex contributors.tex: contributors.yml contributors.tex.j2 - python3 contributors.py $< -o $@ + python3 contributors.py $< -t contributors.tex.j2 -o $@ plots:: $(MAKE) -C group_composition_plot diff --git a/contributors.py b/contributors.py index 8e96f5b..4a0eaed 100755 --- a/contributors.py +++ b/contributors.py @@ -11,6 +11,8 @@ def main(): parser = argparse.ArgumentParser() parser.add_argument("contributors", type=Path, help="yml file containing the contributors") + parser.add_argument("-t", "--template", type=Path, required=True, + help="name of template to use") parser.add_argument("-o", "--output", type=Path, help="the name of the output file") args = parser.parse_args() @@ -50,7 +52,7 @@ def main(): keep_trailing_newline=True, ) - contribs = env.get_template("contributors.tex.j2").render(data=data) + contribs = env.get_template(args.template.name).render(data=data) if args.output is not None: args.output.write_text(contribs) From ee1676acd7405949567c388e58c213a29a3e5aab Mon Sep 17 00:00:00 2001 From: Magnus Hagdorn Date: Mon, 25 Aug 2025 10:22:39 +0200 Subject: [PATCH 05/17] add template for plos contributor list --- contributors_plos.tex.j2 | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 contributors_plos.tex.j2 diff --git a/contributors_plos.tex.j2 b/contributors_plos.tex.j2 new file mode 100644 index 0000000..ffec428 --- /dev/null +++ b/contributors_plos.tex.j2 @@ -0,0 +1,17 @@ +% README: The file contributors.tex is automatically generated by running contributors.py. +% Changed within will be OVERWRITTEN. +% For changes to the tex template, change contributors.tex.j2. +% For changes to the author information, change contributors.yml. +% +% Note: the zero-width character <200b> is in here on purpose (to not mess up authors without +% affiliation) +{%- for author in data.authors %} +{{ author.author }}​{% if author.affiliations %}\textsuperscript{ {{ author.affiliations|join(", ") }} }{% endif %} +{%- endfor %} +\\ +\bigskip +{%- for index, affiliation in data.affiliations.items() %} +\textbf{ {{ index }} } {{ affiliation.name }} +\\ +{%- endfor %} +\bigskip From fe993fafc3a77858f8d240b8808adea53f3c34da Mon Sep 17 00:00:00 2001 From: Magnus Hagdorn Date: Mon, 25 Aug 2025 16:35:42 +0200 Subject: [PATCH 06/17] first round of adjustments --- paper.tex | 260 ++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 204 insertions(+), 56 deletions(-) diff --git a/paper.tex b/paper.tex index 8e1eade..7c47044 100644 --- a/paper.tex +++ b/paper.tex @@ -1,55 +1,205 @@ \PassOptionsToPackage{dvipsnames,svgnames,x11names}{xcolor} -\documentclass[a4paper]{article} +\documentclass[10pt,letterpaper]{article} +\usepackage[top=0.85in,left=2.75in,footskip=0.75in]{geometry} + \usepackage[T1]{fontenc} \usepackage[ngerman,british]{babel} \usepackage{authblk} \usepackage{csquotes} \usepackage[alldates=iso,seconds=true,sorting=none]{biblatex} \usepackage{graphicx} -\usepackage[margin=2.5cm]{geometry} -\DeclareUnicodeCharacter{200B}{{\hskip 0pt}} +% amsmath and amssymb packages, useful for mathematical formulas and symbols +\usepackage{amsmath,amssymb} + +% Use adjustwidth environment to exceed column width (see example table in text) +\usepackage{changepage} + +% textcomp package and marvosym package for additional characters +\usepackage{textcomp,marvosym} + +% cite package, to clean up citations in the main text. Do not remove. +\usepackage{cite} + +% Use nameref to cite supporting information files (see Supporting Information section for more info) +\usepackage{nameref,hyperref} + +% line numbers +\usepackage[right]{lineno} + +% ligatures disabled +\usepackage[nopatch=eqnum]{microtype} +\DisableLigatures[f]{encoding = *, family = * } + +% color can be used to apply background shading to table cells only +\usepackage[table]{xcolor} + +% array package and thick rules for tables +\usepackage{array} + + +% create "+" rule type for thick vertical lines +\newcolumntype{+}{!{\vrule width 2pt}} + +% create \thickcline for thick horizontal lines of variable length +\newlength\savedwidth +\newcommand\thickcline[1]{% + \noalign{\global\savedwidth\arrayrulewidth\global\arrayrulewidth 2pt}% + \cline{#1}% + \noalign{\vskip\arrayrulewidth}% + \noalign{\global\arrayrulewidth\savedwidth}% +} -\usepackage{libertine} -\usepackage{orcidlink} -\usepackage{rorlink} -\renewcommand\Affilfont{\small} +% \thickhline command for thick horizontal lines that span the table +\newcommand\thickhline{\noalign{\global\savedwidth\arrayrulewidth\global\arrayrulewidth 2pt}% +\hline +\noalign{\global\arrayrulewidth\savedwidth}} + +% Remove comment for double spacing +%\usepackage{setspace} +%\doublespacing + +% Text layout +\raggedright +\setlength{\parindent}{0.5cm} +\textwidth 5.25in +\textheight 8.75in + +% Bold the 'Figure #' in the caption and separate it from the title/caption with a period +% Captions will be left justified +\usepackage[aboveskip=1pt,labelfont=bf,labelsep=period,justification=raggedright,singlelinecheck=off]{caption} +\renewcommand{\figurename}{Fig} + +% Please use the included `plos2025.bst` as your BibTeX style +%\bibliographystyle{plos2025} + +% Remove brackets from numbering in List of References +\makeatletter +\renewcommand{\@biblabel}[1]{\quad#1.} +\makeatother + + +% Header and Footer with logo +\usepackage{lastpage,fancyhdr,graphicx} +\usepackage{epstopdf} +%\pagestyle{myheadings} +\pagestyle{fancy} +\fancyhf{} +%\setlength{\headheight}{27.023pt} +%\lhead{\includegraphics[width=2.0in]{PLOS-submission.eps}} +\rfoot{\thepage/\pageref{LastPage}} +\renewcommand{\headrulewidth}{0pt} +\renewcommand{\footrule}{\hrule height 2pt \vspace{2mm}} +\fancyheadoffset[L]{2.25in} +\fancyfootoffset[L]{2.25in} +\lfoot{\today} -\usepackage{hyperref} -\urlstyle{same} \usepackage{xspace} \usepackage{caption,tikzpagenodes,ifthen} -\usepackage{mdframed} +%% Include all user-defined macros below \newcommand*{\eg}{e.\,g.,\xspace} \newcommand*{\ie}{i.\,e.,\xspace} -\hypersetup{% - %pdftitle={}, - %pdfkeywords={}, - colorlinks=true, - linkcolor={darkgray}, - filecolor={Maroon}, - citecolor={Blue}, - urlcolor={Blue}, -} +%% END MACROS SECTION \addbibresource{bibliography.bib} \addbibresource{positionpaper.bib} \setcounter{biburllcpenalty}{100} -\title{Developing central Research Software Engineering units in German research institutions} -\input{contributors.tex} +%\usepackage[alldates=iso,seconds=true,sorting=none]{biblatex} +%\usepackage[margin=2.5cm]{geometry} -\date{\today} +\DeclareUnicodeCharacter{200B}{{\hskip 0pt}} + +%\usepackage{libertine} +%\usepackage{orcidlink} +%\usepackage{rorlink} +%\renewcommand\Affilfont{\small} -\begin{document} -\maketitle +%\urlstyle{same} -\abstract{% +\usepackage{mdframed} + +\begin{document} +\vspace*{0.2in} + +% Title must be 250 characters or less. +\begin{flushleft} +{\Large +\textbf{Developing central Research Software Engineering units in German research institutions} % Please use "sentence case" for title and headings (capitalize only the first word in a title (or heading), the first word in a subtitle (or subheading), and any proper nouns). +} +\newline +% Insert author names, affiliations and corresponding author email (do not include titles, positions, or degrees). +\\ +Dominic Kempf​\textsuperscript{ 1* } +Frank Löffler​\textsuperscript{ 2, 3 } +René Caspart​\textsuperscript{ 4 } +Bernd Flemisch​\textsuperscript{ 5 } +Florian Goth​\textsuperscript{ 6 } +Jan Linxweiler​\textsuperscript{ 7, 3 } +Philipp Matthias Schäfer​\textsuperscript{ 2 } +Robert Speck​\textsuperscript{ 8 } +Alexander Struck​\textsuperscript{ 9 } +Markus J. Ankenbrand​\textsuperscript{ 10 } +Leyla Jael Castro​\textsuperscript{ 11 } +Iris Ehlert​\textsuperscript{ 12 } +Jean-Noël Grad​\textsuperscript{ 13 } +Magnus Hagdorn​\textsuperscript{ 14 } +Axel Loewe​\textsuperscript{ 15 } +Michael Schlottke-Lakemper​\textsuperscript{ 16 } +Uwe Schmitt​\textsuperscript{ 17 } +Philipp S. Sommer​\textsuperscript{ 18 } +\\ +\bigskip +\textbf{ 1 } Scientific Software Center, Heidelberg University, Germany +\\ +\textbf{ 2 } Competence Center Digital Research, Friedrich Schiller University Jena, Germany +\\ +\textbf{ 3 } de-RSE e.V.---Society for Research Software in Germany +\\ +\textbf{ 4 } Scientific Computing Center, Karlsruhe Institute of Technology, Germany +\\ +\textbf{ 5 } Institute for Modelling Hydraulic and Environmental Systems, University of Stuttgart, Germany +\\ +\textbf{ 6 } Institute for Theoretical Physics and Astrophysics, University of Würzburg, Germany +\\ +\textbf{ 7 } University Library, Technische Universität Braunschweig, Germany +\\ +\textbf{ 8 } Jülich Supercomputing Centre, Forschungszentrum Jülich GmbH, Germany +\\ +\textbf{ 9 } Cluster of Excellence Matters of Activity. Image Space Material at Humboldt-Universität zu Berlin, Germany +\\ +\textbf{ 10 } Center for Computational and Theoretical Biology, University of Würzburg, Germany +\\ +\textbf{ 11 } Semantic Technologies team, ZB MED Information Centre for Life Sciences, Germany +\\ +\textbf{ 12 } German Climate Computing Center (DKRZ), Germany +\\ +\textbf{ 13 } Institute for Computational Physics, University of Stuttgart, Germany +\\ +\textbf{ 14 } Geschäftsbereich IT, Charité Universitätsmedizin Berlin, Germany +\\ +\textbf{ 15 } Institute of Biomedical Engineering, Karlsruhe Institute of Technology, Germany +\\ +\textbf{ 16 } Centre for Advanced Analytics and Predictive Sciences, University of Augsburg, Germany +\\ +\textbf{ 17 } Scientific IT Services, ETH Zurich, Switzerland +\\ +\textbf{ 18 } Institute of Carbon Cycles, Helmholtz Coastal Data Center, Helmholtz-Zentrum Hereon, Germany +\\ +\bigskip + +% Use the asterisk to denote corresponding authorship and provide email address in note below. +* dominic.kempf@iwr.uni-heidelberg.de + +\end{flushleft} +% Please keep the abstract below 300 words + +\section*{Abstract} This position paper urges decision makers in Germany to establish central Research Software Engineering (RSE) units within their institutions. The focus is not put primarily on the establishment of RSE services in general, as this has been done already elsewhere. Instead, we highlight central RSE units. @@ -59,9 +209,8 @@ We discuss initial observations on possible clusters, but further studies are needed. Finally, we discuss realisation strategies. While this paper focuses mostly on the German academic environment, some general strategies should also apply elsewhere. -} -\section{Introduction} +\section*{Introduction} Research software has been written and used for decades in an increasing range of disciplines. It has been established that most research requires research software for its results~\autocite{Hannay2009, Hettrick2015}. To solve pressing research challenges, better software is crucial~\autocite{Goble2014}. @@ -101,7 +250,7 @@ \section{Introduction} All of these implementations are considered, taking into account the large variety of research environments in Germany, which include not only universities, but also research consortia and other research performing organisations. We use the term central \emph{RSE unit} interchangeably with the term \emph{RSE hub} even though for large federated research organisations there might be a more complex arrangement such as a network of RSE hubs. -\section{Motivation for central RSE units} +\section*{Motivation for central RSE units} \label{sec:motivation} \begin{quotation} \noindent \textit{Better Software, Better Research}\\(Mission statement of the UK Software Sustainability Institute) @@ -116,7 +265,7 @@ \section{Motivation for central RSE units} However, the software is also expected to rate high on a multitude of quality metrics such as correctness, reproducibility, maintainability, extensibility, usability, portability, interoperability, security, performance, and scalability~\autocite[Chapter 16]{Schulmeyer2008}. Handling this increased complexity whilst ensuring timely delivery requires dedicated RSEs in central RSE units. -\subsection{Pooling: a necessary ingredient} +\subsection*{Pooling: a necessary ingredient} The main focus of this paper lies on central RSE teams since the benefits of RSEs to research in general are described elsewhere, \eg{} in~\autocite{Anzt2021}. The main advantages of central RSE units all stem from the pooling of resources. There are at least three aspects to RSE pooling that research institutions can benefit from: funding, diverse knowledge, and a central point of contact. @@ -150,12 +299,12 @@ \subsection{Pooling: a necessary ingredient} However, an embedded RSE can feel very lonely when they do not have anybody to discuss technical problems. A central RSE unit also provides a social space for RSEs where this exchange can easily happen. -\subsection{Pooling: an already tested idea} +\subsection*{Pooling: an already tested idea} The idea to pool resources in specific areas within an organisation is not new. In industry, software engineering underwent a similar transition about 20 years ago, with the creation of specialised, central software development units. In an example from academia, similar arguments can and have been made for research data support. -\subsubsection{Research data management} +\subsubsection*{Research data management} Both data and software play a fundamental role in almost all of research. Over the past decades, Research Data Management (RDM) has evolved into a topic of national interest with NFDI\footnote{Nationale Forschungsdateninfrastruktur: the national research data infrastructure in Germany} consortia for all disciplines and a research data law. Federal state RDM initiatives\footnote{\url{https://forschungsdaten.info/fdm-im-deutschsprachigen-raum/deutschland/}} have established the topic further and provide regional training, networking and other supporting services. @@ -170,7 +319,7 @@ \subsubsection{Research data management} Due to the similar nature of both, data and software, and their importance in today's digital research, it is reasonable to expect a similar trajectory in the development of research software as a topic, as we have witnessed for research data. -\subsubsection{Existing RSE efforts} +\subsubsection*{Existing RSE efforts} Some organisations already have central RSE teams. The field of RSE teams in Germany is currently poorly mapped and very diverse. It includes groups with responsibilities across institutions like the Helmholtz HIFIS group~\autocite{haupt_hifis_consulting_2021, HIFIS}, but mostly groups with responsibilities local to their institution. @@ -195,7 +344,7 @@ \subsubsection{Existing RSE efforts} In the UK, it is common for grant applications to include software development in their budget. This allocated money can then be utilised to delegate/dispatch a central RSE person or group into a research project for a few weeks or months as necessary. -\subsection{External expectations} +\subsection*{External expectations} Some of the latest DFG grant application templates (\eg{} the strategy of excellence~\autocite{DFG_ExStra130}) require discussion of both, data \emph{and} software management (in line with their GWP guidelines~\autocite{dfg_gsp}). In addition, as dedicated DMPs have become mandatory in several funding calls~\autocite{FDM_Info_FDM}, we expect to see a similar development for Software Management Plans (SMPs) in the future. @@ -219,7 +368,7 @@ \subsection{External expectations} The FAIR principles for Research Software (FAIR4RS)~\autocite{ChueHong2022} have been adopted worldwide~\autocite{Barker2024}, including the German Ministry of Education and Research (BMBF) and the German Research Foundation (DFG). The rather complex assessment of FAIRness~\autocite{Wilkinson2023,FAIRmaturity} has also widened from data to software~\autocite{Lamprecht2020}. -\section{Vision}% +\section*{Vision}% \label{sec:vision} In this section, we describe our vision for central RSE units at research institutions in Germany. @@ -235,7 +384,7 @@ \section{Vision}% This provides both a quick overview of an individual group as well as a way to compare groups. The nine modules are described below. -\subsection{Module 1: Foster a local Network of RSEs}% +\subsection*{Module 1: Foster a local Network of RSEs}% \label{sec:network} One of the core responsibilities of an RSE unit is to act as a coordinator of RSE activities within the institution. @@ -262,7 +411,7 @@ \subsection{Module 1: Foster a local Network of RSEs}% This gives an opportunity to gauge how the new colleague can benefit from the RSE unit's teaching services and whom they might want to network with based on their planned work. Similarly an off-boarding process can help to make sure that all acquired knowledge that is relevant to the institution is passed on to someone else, even if possibly not within the specific research group. -\subsection{Module 2: Consultation Services}% +\subsection*{Module 2: Consultation Services}% \label{sec:consultation} With the majority of researchers being self-taught programmers~\autocite{Carver2013}, there is a huge demand for expertise on how to develop better research software. @@ -286,7 +435,7 @@ \subsection{Module 2: Consultation Services}% This in turn leads to improved proposal acceptance rates, thereby amortising the initial investment into RSE units. -\subsection{Module 3: Development Services}% +\subsection*{Module 3: Development Services}% \label{sec:development} There is a huge demand for the development and customisation of research software tailored to the needs of specific research projects. @@ -325,7 +474,7 @@ \subsection{Module 3: Development Services}% Besides the technical benefits of this central deployment procedure, the institution benefits from the increased visibility and the ability to build a brand with its technological output. \end{mdframed} -\subsection{Module 4: Teaching Services}% +\subsection*{Module 4: Teaching Services}% \label{sec:teaching} A central RSE unit can provide or organise training for researchers and embedded RSEs. @@ -337,7 +486,7 @@ \subsection{Module 4: Teaching Services}% In both cases, the expert RSEs from the central RSE unit can pass on their knowledge precisely adapted to the concrete needs of those that they support. Finally, in organisations that educate RSEs, members of a central RSE unit may contribute to the curriculum of the institutional study programmes and teach corresponding courses. -\subsection{Module 5: Create a Network of Institutional Partners}% +\subsection*{Module 5: Create a Network of Institutional Partners}% \label{sec:partners} Within a research institution, a lot of groups or departments touch the topic of research software one way or another. @@ -374,7 +523,7 @@ \subsection{Module 5: Create a Network of Institutional Partners}% The challenges of an average researchers often start a long way before reaching that level, and they might not ever need to consider HPC\@. There are obvious reasons to closely collaborate on both consulting and training, yet at the same time a central RSE unit has to provide a much broader portfolio. -\subsection{Module 6: RSE Infrastructure Provisioning}% +\subsection*{Module 6: RSE Infrastructure Provisioning}% \label{sec:infrastructure} IT and (potentially high-performance) computing infrastructure provisioning is usually the purview of an institution's IT unit. @@ -395,7 +544,7 @@ \subsection{Module 6: RSE Infrastructure Provisioning}% Once the mutual collaboration between an RSE unit and an IT unit has been established, a stricter policy-based involvement of the RSE unit for infrastructure requests is envisioned. Overall, by acting as an intermediary for RSE infrastructure related requests, the central RSE unit can augment the central IT unit, providing embedded RSEs with the specific support they require. -\subsection{Module 7: Research Software Engineering Research}% +\subsection*{Module 7: Research Software Engineering Research}% \label{sec:rseresearch} If software engineering research about research software is conducted at the research institution, an RSE unit can serve as a valuable resource and experimentation field to these researchers. @@ -403,7 +552,7 @@ \subsection{Module 7: Research Software Engineering Research}% Additionally, RSEs employed at the hub can be given the opportunity to conduct research on meta aspects of RSE work and publish about them. This allows the staff working at the hub to contribute to and shape the emerging field of RSE research~\autocite{Felderer_2025}. -\subsection{Module 8: Software Maintenance Service}% +\subsection*{Module 8: Software Maintenance Service}% \label{sec:maintenance} Funder policies such as the DFG “Guidelines for Safeguarding Good Research Practice”~\autocite{dfg_gsp} require long-term preservation of used research data and software in an adequate way. @@ -423,7 +572,7 @@ \subsection{Module 8: Software Maintenance Service}% \item A mechanism for selecting and prioritising software projects to be maintained needs to be in place. \end{itemize} -\subsection{Module 9: Communication and Outreach}% +\subsection*{Module 9: Communication and Outreach}% \label{sec:outreach} We identify three categories of communication and outreach activities according to the participating individuals and groups, connecting the RSE unit to (i) the RSEs at the institution, (ii) other entities within the institution, and (iii) regional, national and international initiatives. @@ -447,7 +596,7 @@ \subsection{Module 9: Communication and Outreach}% Through this integrated approach, natESM reinforces the technical backbone of Earth system and climate modelling, ensuring that it remains adaptable, scalable, and future-proof. \end{mdframed} -\section{Existing Implementations}% +\section*{Existing Implementations}% \label{sec:existing} \begin{figure} @@ -474,7 +623,7 @@ \section{Existing Implementations}% When setting up a new RSE unit, it is important to find the best service portfolio composition for the local environment. This depends on the demand by scientists at the institution, existing structures and the available funding. -\section{Realisation Strategy}% +\section*{Realisation Strategy}% \label{sec:realisation} We propose building blocks for individual realisation strategies for central institutional RSE units. @@ -482,7 +631,7 @@ \section{Realisation Strategy}% Following that, we describe a potential transition pathway, starting from existing structures that have grown in research alliances such as, \eg{} DFG-funded Collaborative Research Centres or also in research departments of an institution. This is complemented by discussions of the possibility of outsourcing RSE services and of the challenging task of identifying and hiring suitable RSE candidates. -\subsection{Funding Sources}% +\subsection*{Funding Sources}% \label{sec:funding} We see four basic options for financing RSE positions, which we will briefly explain below: @@ -521,13 +670,13 @@ \subsection{Funding Sources}% In addition to these funding options, we encourage funding agencies to provide seed funding for the establishment of RSE structures. Such seed grants ease the decision making process in organisations and give RSEs the leeway to establish collaborations with researchers without the direct need to ask for remuneration. -\subsection{Transition Pathway} +\subsection*{Transition Pathway} We propose a potential transition path, beginning with purely embedded RSEs---distributed across the institution and linked to individual research groups and their projects---and leading toward a centralised institutional RSE unit. After starting with initial measures not necessarily requiring dedicated funding, we discuss developing a business plan and how the RSE unit can be established. We conclude with measures for promoting its growth. -\subsubsection{Initial Measures} +\subsubsection*{Initial Measures} The following measures initialise the two modules presented in \autoref{sec:network} and \autoref{sec:teaching}. While dedicated funding certainly is beneficial already for this step, it is not strictly necessary. Once the two measures are in place, they can be used to illustrate the need for institutional RSE activities and therefore support funding proposals. @@ -545,7 +694,7 @@ \subsubsection{Initial Measures} This step can be facilitated and formalised by offering introductory courses with a recognised curriculum as provided by The Carpentries\footnote{Carpentry examples: \url{https://software-carpentry.org/lessons/}} or CodeRefinery\footnote{CodeRefinery examples: \url{https://coderefinery.org/lessons/}}. -\subsubsection{Developing a Business Plan} +\subsubsection*{Developing a Business Plan} Decision processes at institutions usually require a business plan on which to base the decision on whether to establish an RSE unit. The business plan should include an outline of the RSE unit, its responsibilities and offerings as a subset of the nine modules presented in \autoref{sec:vision}, the funding, and the resulting benefits for the institution and its researchers. @@ -566,7 +715,7 @@ \subsubsection{Developing a Business Plan} One of the decisions to be made is if the unit head is supposed to be part of the unit itself or if the unit will be headed by somebody outside of it. Additionally, installing an advisory board can be proposed in the plan, recruiting from the prospective institutional partners. -\subsubsection{Establishing the Unit} +\subsubsection*{Establishing the Unit} Once the business plan has been approved by the institution, the RSE unit can be established accordingly. The initial staffing depends crucially on the local institutional conditions. One promising possibility is to start with two positions. @@ -587,7 +736,7 @@ \subsubsection{Establishing the Unit} Such a communication should facilitate collaboration among RSEs while also keeping non-RSEs in the loop. -\subsubsection{Growth of the Unit} +\subsubsection*{Growth of the Unit} \paragraph{Acquisition of further funding} The most promising possibilities to acquire further funding seem to be explicitly requesting person-months in externally funded projects and dedicated RSE calls, as discussed in \autoref{sec:funding}. @@ -611,7 +760,7 @@ \subsubsection{Growth of the Unit} In addition, SIS offers services in the areas of data science, machine learning, bioinformatics, trusted compute environments, and training and consulting. \end{mdframed} -\subsection{Outsourcing} +\subsection*{Outsourcing} Another possibility for the realisation of local RSE Service providers is by forming a spin-off and pooling the RSE Skills into an external company, which has benefits but also drawbacks. This is an idea that so far lacks examples but for completeness we list some of the advantages and disadvantages. @@ -628,7 +777,7 @@ \subsection{Outsourcing} It is of particular importance to agree on requirements and handover criteria, including quality assurance and license specifications. On top of these drawbacks, there are soft factors, like whether an external company is accepted by scientists. -\subsection{Staff Acquisition/People} +\subsection*{Staff Acquisition/People} RSE units need to be staffed, but where do potential employees come from? So far, researchers accidentally find themselves in the role of an RSE because they pursued software development as part of their research. @@ -650,7 +799,7 @@ \subsection{Staff Acquisition/People} Moreover, data science curricula already exist and more are in the process of being created. A curated and continuously updated list of these programs is available at~\cite{learnandteachlearn}. -\section{Conclusions} +\section*{Conclusions} \label{sec:conclusions} In this paper, we have outlined a vision for central RSE units in research institutions, focusing particularly on the German research landscape. @@ -665,7 +814,6 @@ \section{Conclusions} We encourage decision makers to strategically invest in and formalise central RSE units, recognising their role as indispensable partners in modern research environments. By unifying previously scattered RSE efforts into a coordinated approach with clear mandates, stable funding, and long-term career prospects, institutions have the opportunity to significantly enhance their research capabilities and competitiveness in an increasingly digital scientific world. - -\printbibliography[heading=bibintoc] +\printbibliography \end{document} From 78b8327a35f2b8f6b45cbd0fda55349e49afbdac Mon Sep 17 00:00:00 2001 From: Magnus Hagdorn Date: Tue, 26 Aug 2025 10:31:44 +0200 Subject: [PATCH 07/17] use biber to convert bibliography to bibtex --- Makefile | 14 ++++++++++++-- biberconf.xml | 44 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+), 2 deletions(-) create mode 100644 biberconf.xml diff --git a/Makefile b/Makefile index a78af30..68d284a 100644 --- a/Makefile +++ b/Makefile @@ -2,13 +2,23 @@ all: plots paper.pdf clean: latexmk -c - rm paper.pdf + rm -f paper.pdf plos.bib norm.bib -paper.pdf: paper.tex positionpaper.bib contributors.tex +paper.pdf: paper.tex positionpaper.bib contributors.tex plos.bib latexmk -pdflatex paper.tex contributors.tex: contributors.yml contributors.tex.j2 python3 contributors.py $< -t contributors.tex.j2 -o $@ +# this step is to convert the input files to proper biblatex files +# so we can turn them into bibtex files later on +norm.bib: positionpaper.bib bibliography.bib + biber --tool $^ --output-file $@ + +plos.bib: norm.bib + biber --tool $< --output-file $@ \ + --configfile=biberconf.xml \ + --output-field-replace=location:address,journaltitle:journal + plots:: $(MAKE) -C group_composition_plot diff --git a/biberconf.xml b/biberconf.xml new file mode 100644 index 0000000..9cfb3cc --- /dev/null +++ b/biberconf.xml @@ -0,0 +1,44 @@ + + + + lower + 1 + 1 + bibtex + + + + + + + + + + + + + + + + + + + + + + + + + + + From f41b08083dcc22267870e43f39bc6c9e5b894b59 Mon Sep 17 00:00:00 2001 From: Magnus Hagdorn Date: Tue, 26 Aug 2025 10:32:51 +0200 Subject: [PATCH 08/17] fix author list and remove duplicate --- bibliography.bib | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/bibliography.bib b/bibliography.bib index 09958ac..c307184 100644 --- a/bibliography.bib +++ b/bibliography.bib @@ -4725,7 +4725,7 @@ @online{SSIDataScience @online{SSIRSEandDS, organization = {Software Sustainability Institute }, -author = {Matthew Archer, Stephen Dowsland, Rosa Filgueira, R. Stuart Geiger, Alejandra Gonzalez-Beltran, Robert Haines, James Hetherington, Christopher Holdgraf, Sanaz Jabbari Bayandor, David Mawdsley, Heiko Mueller, Tom Redfern, Martin O'Reilly, Valentina Staneva, Mark Turner, Jake VanderPlas, Kirstie Whitaker}, +author = {Archer, Matthew and Dowsland, Stephen and Filgueira, Rosa and Geiger, R. Stuart and Gonzalez-Beltran, Alejandra and Haines, Robert and Hetherington, James and Holdgraf, Christopher and Bayandor, Sanaz Jabbari and Mawdsley, David and Mueller, Heiko and Redfern, Tom and O'Reilly, Martin and Staneva, Valentina and Turner, Mark and VanderPlas, Jake and Whitaker, Kirstie}, title = {Research Software Engineers and Data Scientists: More in Common}, url = {https://www.software.ac.uk/blog/2018-04-05-research-software-engineers-and-data-scientists-more-common}, urldate = {2023-08-04} @@ -5680,15 +5680,6 @@ @article{smith_SoftwareCitationPrinciples2016 doi = {10.7717/peerj-cs.86} } -@Article{goth_foundational_competencies_2024, - title={Foundational Competencies and Responsibilities of a Research Software Engineer}, - author={Goth, Florian and Alves, Renato and Braun, Matthias and Castro, Leyla Jael and Chourdakis, Gerasimos and Christ, Simon and Cohen, Jeremy and Druskat, Stephan and Erxleben, Fredo and Grad, Jean-No{\"e}l and Hagdorn, Magnus and Hodges, Toby and Juckeland, Guido and Kempf, Dominic and Lamprecht, Anna-Lena and Linxweiler, Jan and L{\"o}ffler, Frank and Martone, Michele and Schwarzmeier, Moritz and Seibold, Heidi and Thiele, Jan Philipp and von Waldow, Harald and Wittke, Samantha}, - year={2024}, - journal={arXiv}, - volume={2311.11457}, - doi={10.48550/arXiv.2311.11457}, -} - @InProceedings{haupt_hifis_consulting_2021, author = {Haupt, Carina and Stoffers, Martin}, title = {Roles in Research Software Engineering ({RSE}) Consultancies}, From a654b478a1deb454e27435c814f412c15ca7d720 Mon Sep 17 00:00:00 2001 From: Magnus Hagdorn Date: Tue, 26 Aug 2025 10:33:31 +0200 Subject: [PATCH 09/17] use bibtex --- paper.tex | 97 +++++++++++++++++++++++++++---------------------------- 1 file changed, 48 insertions(+), 49 deletions(-) diff --git a/paper.tex b/paper.tex index 7c47044..4716f8c 100644 --- a/paper.tex +++ b/paper.tex @@ -6,8 +6,9 @@ \usepackage[ngerman,british]{babel} \usepackage{authblk} \usepackage{csquotes} -\usepackage[alldates=iso,seconds=true,sorting=none]{biblatex} \usepackage{graphicx} +% to deal with underscore in dois +\usepackage{underscore} % amsmath and amssymb packages, useful for mathematical formulas and symbols \usepackage{amsmath,amssymb} @@ -71,7 +72,7 @@ \renewcommand{\figurename}{Fig} % Please use the included `plos2025.bst` as your BibTeX style -%\bibliographystyle{plos2025} +\bibliographystyle{plos2025} % Remove brackets from numbering in List of References \makeatletter @@ -104,10 +105,6 @@ %% END MACROS SECTION -\addbibresource{bibliography.bib} -\addbibresource{positionpaper.bib} -\setcounter{biburllcpenalty}{100} - %\usepackage[alldates=iso,seconds=true,sorting=none]{biblatex} %\usepackage[margin=2.5cm]{geometry} @@ -210,20 +207,22 @@ \section*{Abstract} Finally, we discuss realisation strategies. While this paper focuses mostly on the German academic environment, some general strategies should also apply elsewhere. +\linenumbers + \section*{Introduction} Research software has been written and used for decades in an increasing range of disciplines. -It has been established that most research requires research software for its results~\autocite{Hannay2009, Hettrick2015}. -To solve pressing research challenges, better software is crucial~\autocite{Goble2014}. +It has been established that most research requires research software for its results~\cite{Hannay2009, Hettrick2015}. +To solve pressing research challenges, better software is crucial~\cite{Goble2014}. During the past decade, research software gained ever-growing attention and is becoming accepted as a research result in its own right. -The number of people developing software in academia is continuously rising~\autocite{Hannay2009, Hettrick2015}. +The number of people developing software in academia is continuously rising~\cite{Hannay2009, Hettrick2015}. Research software engineering encompasses creating, adapting or maintaining research software. -It also includes consultation and training with the aim to enable researchers to some of these tasks themselves~\autocite{goth_foundational_competencies_2024}. +It also includes consultation and training with the aim to enable researchers to some of these tasks themselves~\cite{goth_foundational_competencies_2024}. These actions are very diverse and so are the environments they are performed in. This position paper focuses on groups of research software engineers that provide their services for an entire research organisation or at least a substantial part of it. We advocate the establishment and support of dedicated, central RSE groups in German research organisations, with clearly defined tasks, points of contact, and, in particular, sustained funding, for the benefit of all researchers in their organisation. -Similar initiatives have been formed in other national contexts (see~\autocite{barkerkatz2024,martin2023} and references therein). +Similar initiatives have been formed in other national contexts (see~\cite{barkerkatz2024,martin2023} and references therein). We provide an overview of the various tasks these teams have and discuss potential realisation strategies, learning from already existing RSE units. Depending on the national research environments and processes that readers are familiar with, the notion of the terms \emph{software} and \emph{research} might differ. @@ -233,7 +232,7 @@ \section*{Introduction} Source code, documentation, tests, executables, and all other artefacts that are created during the development process and that are necessary to understand its purpose. \paragraph{Research software} Foundational algorithms, the software itself, as well as scripts and computational workflows that were created during the research process or for a research purpose, across all domains of research. -This definition is broader than in~\autocite{FAIR4RS} and is the outcome of a recent discussion in~\autocite{Gruenpeter2021}. +This definition is broader than in~\cite{FAIR4RS} and is the outcome of a recent discussion in~\cite{Gruenpeter2021}. \paragraph{Research software engineers} People who create or improve research software and/or the structures that the software interacts with the computational ecosystem of a research domain. They are highly skilled team members who may also conduct their own research as part of their role. @@ -257,27 +256,27 @@ \section*{Motivation for central RSE units} \end{quotation} The quote above is the shortest possible summary of this chapter: most if not all motivation to provide RSE services stems from the goal of improving research. -Tasks that Research Software Engineers (RSEs) perform include training, \eg{} to improve the quality of code produced by researchers~\autocite{Ostlund2023}, consultation services, \eg{} regarding frameworks or algorithm selection, and the development of existing or new software. -For an overview of typical tasks of RSEs and the competencies required, see~\autocite{goth_foundational_competencies_2024}, especially section\ 4.4:\ “RSE tasks and responsibilities”. +Tasks that Research Software Engineers (RSEs) perform include training, \eg{} to improve the quality of code produced by researchers~\cite{Ostlund2023}, consultation services, \eg{} regarding frameworks or algorithm selection, and the development of existing or new software. +For an overview of typical tasks of RSEs and the competencies required, see~\cite{goth_foundational_competencies_2024}, especially section\ 4.4:\ “RSE tasks and responsibilities”. Research software is getting increasingly complex. This is partly because the scientific problems being tackled using software are getting bigger. -However, the software is also expected to rate high on a multitude of quality metrics such as correctness, reproducibility, maintainability, extensibility, usability, portability, interoperability, security, performance, and scalability~\autocite[Chapter 16]{Schulmeyer2008}. +However, the software is also expected to rate high on a multitude of quality metrics such as correctness, reproducibility, maintainability, extensibility, usability, portability, interoperability, security, performance, and scalability~\cite[Chapter 16]{Schulmeyer2008}. Handling this increased complexity whilst ensuring timely delivery requires dedicated RSEs in central RSE units. \subsection*{Pooling: a necessary ingredient} -The main focus of this paper lies on central RSE teams since the benefits of RSEs to research in general are described elsewhere, \eg{} in~\autocite{Anzt2021}. +The main focus of this paper lies on central RSE teams since the benefits of RSEs to research in general are described elsewhere, \eg{} in~\cite{Anzt2021}. The main advantages of central RSE units all stem from the pooling of resources. There are at least three aspects to RSE pooling that research institutions can benefit from: funding, diverse knowledge, and a central point of contact. First, pooling of \textbf{funding} allows organisations to invest in building up institutional knowledge by supporting RSEs to become experts. A central RSE team on long-term contracts will act as a knowledge hub due to their accumulated experience in and support of several disciplines as well as established contacts within the organisation. -This is comparable to commercial/industry R\&D departments or so-called inhouse consulting~\autocite{Grima_2011}, where key software architects and developers establish a knowledge hub that can be consulted by project teams as necessary. +This is comparable to commercial/industry R\&D departments or so-called inhouse consulting~\cite{Grima_2011}, where key software architects and developers establish a knowledge hub that can be consulted by project teams as necessary. Subject matter experts like software architects, database administrators and other tooling specialists are organised centrally and share their knowledge with members of decentralised projects. It makes economic sense to organise such staff centrally, since not every project has a need for a full-time specialist or can afford one over an extended period of time. Most academic research organisations have established centralised tooling, \eg{} storage or High-Performance-Computing\ (HPC), but only a few consider software development and consultancy a relevant service yet. A second and equally important aspect to pooling RSEs is that of \textbf{diverse knowledge}. -RSE units act as knowledge hubs in a network of academic developers within an organisation~\autocite{Elsholz2006}. +RSE units act as knowledge hubs in a network of academic developers within an organisation~\cite{Elsholz2006}. Groups of RSEs with tasks spanning the entire organisation necessarily have to offer diverse knowledge. Obtaining this diversity of knowledge and experience can also be a challenge, but once it has been established it quickly becomes an asset to the organisation. RSEs in centralised groups are interdisciplinary specialists. @@ -322,23 +321,23 @@ \subsubsection*{Research data management} \subsubsection*{Existing RSE efforts} Some organisations already have central RSE teams. The field of RSE teams in Germany is currently poorly mapped and very diverse. -It includes groups with responsibilities across institutions like the Helmholtz HIFIS group~\autocite{haupt_hifis_consulting_2021, HIFIS}, but mostly groups with responsibilities local to their institution. +It includes groups with responsibilities across institutions like the Helmholtz HIFIS group~\cite{haupt_hifis_consulting_2021, HIFIS}, but mostly groups with responsibilities local to their institution. Their anchoring within institutions also differs: -Some are part of an existing interdisciplinary research institution (like the Scientific Software Center in Heidelberg~\autocite{keegan_ssc_whitepaper,HeidelbergSSC}). -Others are part of the central university research support infrastructure and are goverened by the institutional leadership (like the Competence Center Digital Research (zedif) in Jena~\autocite{zedifUniJena}). -Yet others have a project character, like Suresoft in Braunschweig~\autocite{Blech2022,SURESOFTLink}. +Some are part of an existing interdisciplinary research institution (like the Scientific Software Center in Heidelberg~\cite{keegan_ssc_whitepaper,HeidelbergSSC}). +Others are part of the central university research support infrastructure and are goverened by the institutional leadership (like the Competence Center Digital Research (zedif) in Jena~\cite{zedifUniJena}). +Yet others have a project character, like Suresoft in Braunschweig~\cite{Blech2022,SURESOFTLink}. Another national pioneer is the Göttingen State and University Library where RSE services are part of the library-service portfolio. Most of these groups, or at least their RSE services, are still relatively young. -However, some groups can already report a remarkable increase in software quality, better grant applications, less brain drain and overall better employee satisfaction levels~\autocite{schimavoigt2023}. +However, some groups can already report a remarkable increase in software quality, better grant applications, less brain drain and overall better employee satisfaction levels~\cite{schimavoigt2023}. RSE services which benefit all disciplines/departments may represent a unique selling point for organisations competing for the brightest minds. Besides institutions, there are also other communities related to RSE\@. The HPC community, arguably a sub-community of the RSE-community, has a history of offering training and consulting to prospective and active users of the hardware they support. -National Competence Centres~\autocite{EuroCCWeb} form a network of HPC-RSE consulting groups to share expertise with academic and industry actors~\autocite{eurocc_success_stories_2023,eurocc_success_stories_2024}. +National Competence Centres~\cite{EuroCCWeb} form a network of HPC-RSE consulting groups to share expertise with academic and industry actors~\cite{eurocc_success_stories_2023,eurocc_success_stories_2024}. While we focus on Germany in this paper, it is beneficial to review how other countries approach research software. -In the UK, which we choose as example for being the oldest in terms of RSE, many universities started initiating dedicated RSE units about a decade ago~\autocite{Crouch2013, KDL}. +In the UK, which we choose as example for being the oldest in terms of RSE, many universities started initiating dedicated RSE units about a decade ago~\cite{Crouch2013, KDL}. The successful establishment of these units is a role model for similar research performing organisations worldwide. A range of already existing RSE units in the UK can be seen on this (incomplete) map: \url{https://society-rse.org/community/rse-groups/}. In the UK, it is common for grant applications to include software development in their budget. @@ -346,27 +345,27 @@ \subsubsection*{Existing RSE efforts} \subsection*{External expectations} -Some of the latest DFG grant application templates (\eg{} the strategy of excellence~\autocite{DFG_ExStra130}) require discussion of both, data \emph{and} software management (in line with their GWP guidelines~\autocite{dfg_gsp}). -In addition, as dedicated DMPs have become mandatory in several funding calls~\autocite{FDM_Info_FDM}, we expect to see a similar development for Software Management Plans (SMPs) in the future. -As of today, they are already recommended~\autocite{FDM_Info_SMP}. +Some of the latest DFG grant application templates (\eg{} the strategy of excellence~\cite{DFG_ExStra130}) require discussion of both, data \emph{and} software management (in line with their GWP guidelines~\cite{dfg_gsp}). +In addition, as dedicated DMPs have become mandatory in several funding calls~\cite{FDM_Info_FDM}, we expect to see a similar development for Software Management Plans (SMPs) in the future. +As of today, they are already recommended~\cite{FDM_Info_SMP}. Policies for research software management and guidelines involving responsible research practices detailing software handling are the precursors for a research software engineering environment. See for example position papers by - the Helmholtz Open Science Office~\autocite{Helmholtz2019a,Helmholtz2019b}, - the AllianzInitiative~\autocite{Konrad2021}, - the DLR~\autocite{Schlauch2018b}, - the University Utrecht~\autocite{Utrecht2016b}, - and the German Research Council~\autocite{dfg_gsp}. + the Helmholtz Open Science Office~\cite{Helmholtz2019a,Helmholtz2019b}, + the AllianzInitiative~\cite{Konrad2021}, + the DLR~\cite{Schlauch2018b}, + the University Utrecht~\cite{Utrecht2016b}, + and the German Research Council~\cite{dfg_gsp}. Another development taking place worldwide is the encouragement of authors to submit both, data and software, for peer review. -As an example, the journal “Nature” initiated such a policy\footnote{\url{https://www.nature.com/nature-portfolio/editorial-policies/reporting-standards}} in 2018~\autocite{Nature2018}. +As an example, the journal “Nature” initiated such a policy\footnote{\url{https://www.nature.com/nature-portfolio/editorial-policies/reporting-standards}} in 2018~\cite{Nature2018}. RSE groups are able to offer researchers consulting tailored to their specific needs on how to implement and document those policies. This is especially relevant in the context of reproducibility of software-based research. The global FAIR movement originated from RDM and widened their focus to include research software. However, it also has become clear in that process that software is not “just another type of data” and that the FAIR principles are not sufficient for software. -The FAIR principles for Research Software (FAIR4RS)~\autocite{ChueHong2022} have been adopted worldwide~\autocite{Barker2024}, including the German Ministry of Education and Research (BMBF) and the German Research Foundation (DFG). -The rather complex assessment of FAIRness~\autocite{Wilkinson2023,FAIRmaturity} has also widened from data to software~\autocite{Lamprecht2020}. +The FAIR principles for Research Software (FAIR4RS)~\cite{ChueHong2022} have been adopted worldwide~\cite{Barker2024}, including the German Ministry of Education and Research (BMBF) and the German Research Foundation (DFG). +The rather complex assessment of FAIRness~\cite{Wilkinson2023,FAIRmaturity} has also widened from data to software~\cite{Lamprecht2020}. \section*{Vision}% \label{sec:vision} @@ -414,8 +413,8 @@ \subsection*{Module 1: Foster a local Network of RSEs}% \subsection*{Module 2: Consultation Services}% \label{sec:consultation} -With the majority of researchers being self-taught programmers~\autocite{Carver2013}, there is a huge demand for expertise on how to develop better research software. -Here, “better” can refer to a number of quality metrics as already mentioned in Section~\ref{sec:motivation}: correctness, reproducibility, maintainability, extensibility, usability, portability, interoperability, security, performance, or scalability~\autocite[Chapter 16]{Schulmeyer2008}. +With the majority of researchers being self-taught programmers~\cite{Carver2013}, there is a huge demand for expertise on how to develop better research software. +Here, “better” can refer to a number of quality metrics as already mentioned in Section~\ref{sec:motivation}: correctness, reproducibility, maintainability, extensibility, usability, portability, interoperability, security, performance, or scalability~\cite[Chapter 16]{Schulmeyer2008}. In order to raise the quality standards for research that is based on research software, it is of great importance for research institutions to provide access to such expertise with a low barrier to entry. The hub is a natural place to provide this central service. @@ -463,11 +462,11 @@ \subsection*{Module 3: Development Services}% Examples of topics that would benefit from such expertise pooling are, \eg{} mobile app development and UI/UX development. RSE units that offer development services at all scales have proven to be a success story at many research institutions and have rapidly grown in size due to the influx of third party funding. -Notable examples~\autocite{Katz2019} are, \eg{} Manchester~\autocite{Sinclair2022}, Notre-Dame~\autocite{NotreDame2025}, Stanford~\autocite{Stanford2025}, Princeton~\autocite{Princeton2025, Cosden2022a}. +Notable examples~\cite{Katz2019} are, \eg{} Manchester~\cite{Sinclair2022}, Notre-Dame~\cite{NotreDame2025}, Stanford~\cite{Stanford2025}, Princeton~\cite{Princeton2025, Cosden2022a}. \begin{mdframed} \textbf{Success Story:} The University of Manchester Software and Data Science group has successfully established specialised development services within their institution: -The “Mobile Development Service” \autocite{manchester_mobile} team consists of RSEs that focus solely on developing and deploying mobile apps. +The “Mobile Development Service” \cite{manchester_mobile} team consists of RSEs that focus solely on developing and deploying mobile apps. Without a central RSE unit to anchor such specialised expertise, it would be difficult to establish such a service. Also, having this expertise centralised allows for synergies in the deployment procedure for mobile apps: The RSE unit can create institutional accounts with the app stores and manage the time-consuming deployment process including hard-to-setup procedures like code signing. @@ -550,13 +549,13 @@ \subsection*{Module 7: Research Software Engineering Research}% If software engineering research about research software is conducted at the research institution, an RSE unit can serve as a valuable resource and experimentation field to these researchers. It might therefore be of mutual benefit to co-locate SE researchers and RSEs. Additionally, RSEs employed at the hub can be given the opportunity to conduct research on meta aspects of RSE work and publish about them. -This allows the staff working at the hub to contribute to and shape the emerging field of RSE research~\autocite{Felderer_2025}. +This allows the staff working at the hub to contribute to and shape the emerging field of RSE research~\cite{Felderer_2025}. \subsection*{Module 8: Software Maintenance Service}% \label{sec:maintenance} -Funder policies such as the DFG “Guidelines for Safeguarding Good Research Practice”~\autocite{dfg_gsp} require long-term preservation of used research data and software in an adequate way. -For research software, dedicated archiving solutions such as Software Heritage~\autocite{DiCosmo2020,DiCosmo2023} or Zenodo's GitHub integration~\autocite{GitHubZenodo} exist. +Funder policies such as the DFG “Guidelines for Safeguarding Good Research Practice”~\cite{dfg_gsp} require long-term preservation of used research data and software in an adequate way. +For research software, dedicated archiving solutions such as Software Heritage~\cite{DiCosmo2020,DiCosmo2023} or Zenodo's GitHub integration~\cite{GitHubZenodo} exist. In contrast to research data, however, the long-term availability and usability of research software requires more than an adequate archiving method: Software maintenance is an ongoing change process of software after its release. It includes both fixing bugs that are discovered in the software and adapting the software to changes in the execution environment, such as hardware, operating system, toolchain, and software dependencies. @@ -588,7 +587,7 @@ \subsection*{Module 9: Communication and Outreach}% It organises the bidirectional exchange between the local and the global community and is the central hub for information coming both ways. \begin{mdframed} -\textbf{Success Story:} As a national initiative integrating Research Software Engineering (RSE) principles, natESM (the national Earth System Modelling strategy~\autocite{Ehlert2025}) is developing a sustainable and high-performance Earth system modelling capability for Germany while addressing several of the key aspects outlined above. +\textbf{Success Story:} As a national initiative integrating Research Software Engineering (RSE) principles, natESM (the national Earth System Modelling strategy~\cite{Ehlert2025}) is developing a sustainable and high-performance Earth system modelling capability for Germany while addressing several of the key aspects outlined above. By coordinating RSE activities across multiple institutions through a well-structured sprint process, natESM fosters collaboration between scientists and RSEs, ensuring that future Earth system models remain efficient, maintainable, and HPC-compatible. Within this process, natESM also provides structured consultation services, supporting researchers in adopting modern software development practices and strengthening the technical foundations of their models. Beyond development and maintenance, regular training events and workshops equip scientists with the expertise needed to work effectively within the natESM system. @@ -660,9 +659,9 @@ \subsection*{Funding Sources}% This model has been successfully implemented at several UK universities. In order to scale, it needs to be supported by an institutional policy. Large scale collaborative projects can often apply for dedicated technical support positions that align well with the idea of RSE units. - For example, the German Research Foundation allows requesting funding for “central service units or external service providers” in grant proposals aimed at developing research software~\autocite{katerbow_dfg_rse_2024}. + For example, the German Research Foundation allows requesting funding for “central service units or external service providers” in grant proposals aimed at developing research software~\cite{katerbow_dfg_rse_2024}. \item Funding organisations are increasingly recognising the need for sustainable research software development and are setting up correspondingly designated funding programmes. - The DFG has already organised three calls for proposals in 2016~\autocite{DFGCall2016NachhaltigkeitFS}, 2019~\autocite{DFGCall2019Qualitaetssicherung}, and 2022~\autocite{DFGCall2022ResearchSoftware,katerbow_dfg_rse_funding_2018}. + The DFG has already organised three calls for proposals in 2016~\cite{DFGCall2016NachhaltigkeitFS}, 2019~\cite{DFGCall2019Qualitaetssicherung}, and 2022~\cite{DFGCall2022ResearchSoftware,katerbow_dfg_rse_funding_2018}. It is to be expected that even more programs will be launched in the future. An already established RSE unit at an institution increases the chances of being successful in such calls. \end{enumerate} @@ -744,7 +743,7 @@ \subsubsection*{Growth of the Unit} Over time, more and more researchers and proposals are expected to follow the institutional policy such that a consistent stream of income can be generated. \begin{mdframed} -\textbf{Success Story:} Founded in January 2017, the Research Computing department of Princeton University has experienced a tremendous growth from the initial two FTEs to a total of 18 FTEs in the span of five years~\autocite{Cosden2022a}. +\textbf{Success Story:} Founded in January 2017, the Research Computing department of Princeton University has experienced a tremendous growth from the initial two FTEs to a total of 18 FTEs in the span of five years~\cite{Cosden2022a}. This growth is based on a continuous influx of new funded projects once successful projects showcase the additional value of RSE services to researchers. \end{mdframed} @@ -783,7 +782,7 @@ \subsection*{Staff Acquisition/People} So far, researchers accidentally find themselves in the role of an RSE because they pursued software development as part of their research. A more deliberate approach with specific RSE education may be necessary to train people in sufficient numbers for central RSE units. Being an RSE should be a career worth aspiring to, just as any other profession, with a long-term perspective. -This is a topic covered by a separate paper~\autocite{goth_foundational_competencies_2024}, but we provide a brief summary here: +This is a topic covered by a separate paper~\cite{goth_foundational_competencies_2024}, but we provide a brief summary here: These RSEs will bring a diverse set of skills centred around the topics of research, digital tools, and team-based work and hence can easily offer the consulting services mentioned in the previous section and guide people to their implementation in their workgroups. @@ -814,6 +813,6 @@ \section*{Conclusions} We encourage decision makers to strategically invest in and formalise central RSE units, recognising their role as indispensable partners in modern research environments. By unifying previously scattered RSE efforts into a coordinated approach with clear mandates, stable funding, and long-term career prospects, institutions have the opportunity to significantly enhance their research capabilities and competitiveness in an increasingly digital scientific world. -\printbibliography +\bibliography{plos} \end{document} From dd7bd3a7eed74aaa97fc19dfddff8fd787f00a1c Mon Sep 17 00:00:00 2001 From: Magnus Hagdorn Date: Tue, 26 Aug 2025 10:34:13 +0200 Subject: [PATCH 10/17] ignore intermediate bib files --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 983ecfb..fa034db 100644 --- a/.gitignore +++ b/.gitignore @@ -16,6 +16,8 @@ *.dvi *.xdv *-converted-to.* +norm.bib +plos.bib # these rules might exclude image files for figures etc. # *.ps # *.eps From e41e480d7589fefaf11c80d177fb5142d11b799b Mon Sep 17 00:00:00 2001 From: Magnus Hagdorn Date: Wed, 27 Aug 2025 10:24:56 +0200 Subject: [PATCH 11/17] insert list of contributors * add flag for corresponding author * fix template * insert generated list of contributors into text --- Makefile | 4 +-- contributors.py | 2 ++ contributors.yml | 1 + contributors_plos.tex.j2 | 9 ++++-- paper.tex | 61 +--------------------------------------- 5 files changed, 13 insertions(+), 64 deletions(-) diff --git a/Makefile b/Makefile index 68d284a..35b4523 100644 --- a/Makefile +++ b/Makefile @@ -7,8 +7,8 @@ clean: paper.pdf: paper.tex positionpaper.bib contributors.tex plos.bib latexmk -pdflatex paper.tex -contributors.tex: contributors.yml contributors.tex.j2 - python3 contributors.py $< -t contributors.tex.j2 -o $@ +contributors.tex: contributors.yml contributors_plos.tex.j2 + python3 contributors.py $< -t contributors_plos.tex.j2 -o $@ # this step is to convert the input files to proper biblatex files # so we can turn them into bibtex files later on diff --git a/contributors.py b/contributors.py index 4a0eaed..8186f58 100755 --- a/contributors.py +++ b/contributors.py @@ -31,6 +31,8 @@ def main(): for author in data["authors"]: if 'affiliations' in author: affiliations.extend(author["affiliations"]) + if 'corresponding_author' in author and author['corresponding_author']: + data['corresponding_author'] = author['email'] # make sure affiliations are not duplicated - here by checking # for exact name string affiliations = list({aff['name']: aff for aff in affiliations}.values()) diff --git a/contributors.yml b/contributors.yml index 3b8e37e..500f74a 100644 --- a/contributors.yml +++ b/contributors.yml @@ -88,6 +88,7 @@ authors: firstName: Dominic lastName: Kempf initials: DK + corresponding_author: true affiliations: - name: Scientific Software Center, Heidelberg University, Germany ror: https://ror.org/038t36y30 diff --git a/contributors_plos.tex.j2 b/contributors_plos.tex.j2 index ffec428..ea664cc 100644 --- a/contributors_plos.tex.j2 +++ b/contributors_plos.tex.j2 @@ -6,12 +6,17 @@ % Note: the zero-width character <200b> is in here on purpose (to not mess up authors without % affiliation) {%- for author in data.authors %} -{{ author.author }}​{% if author.affiliations %}\textsuperscript{ {{ author.affiliations|join(", ") }} }{% endif %} +{{ author.author }}​{% if author.affiliations %}\textsuperscript{{ "{" }}{{ author.affiliations|join(",") }}{% if author.corresponding_author is defined and author.corresponding_author %}*{% endif %}{{ "}" }}{% endif %} {%- endfor %} \\ \bigskip {%- for index, affiliation in data.affiliations.items() %} -\textbf{ {{ index }} } {{ affiliation.name }} +\textbf{{ "{" }}{{ index }}{{ "}" }} {{ affiliation.name }} \\ {%- endfor %} \bigskip +{% if data.corresponding_author is defined %} + +* {{ data.corresponding_author }} +{% endif %} + diff --git a/paper.tex b/paper.tex index 4716f8c..d1e077e 100644 --- a/paper.tex +++ b/paper.tex @@ -132,66 +132,7 @@ \newline % Insert author names, affiliations and corresponding author email (do not include titles, positions, or degrees). \\ -Dominic Kempf​\textsuperscript{ 1* } -Frank Löffler​\textsuperscript{ 2, 3 } -René Caspart​\textsuperscript{ 4 } -Bernd Flemisch​\textsuperscript{ 5 } -Florian Goth​\textsuperscript{ 6 } -Jan Linxweiler​\textsuperscript{ 7, 3 } -Philipp Matthias Schäfer​\textsuperscript{ 2 } -Robert Speck​\textsuperscript{ 8 } -Alexander Struck​\textsuperscript{ 9 } -Markus J. Ankenbrand​\textsuperscript{ 10 } -Leyla Jael Castro​\textsuperscript{ 11 } -Iris Ehlert​\textsuperscript{ 12 } -Jean-Noël Grad​\textsuperscript{ 13 } -Magnus Hagdorn​\textsuperscript{ 14 } -Axel Loewe​\textsuperscript{ 15 } -Michael Schlottke-Lakemper​\textsuperscript{ 16 } -Uwe Schmitt​\textsuperscript{ 17 } -Philipp S. Sommer​\textsuperscript{ 18 } -\\ -\bigskip -\textbf{ 1 } Scientific Software Center, Heidelberg University, Germany -\\ -\textbf{ 2 } Competence Center Digital Research, Friedrich Schiller University Jena, Germany -\\ -\textbf{ 3 } de-RSE e.V.---Society for Research Software in Germany -\\ -\textbf{ 4 } Scientific Computing Center, Karlsruhe Institute of Technology, Germany -\\ -\textbf{ 5 } Institute for Modelling Hydraulic and Environmental Systems, University of Stuttgart, Germany -\\ -\textbf{ 6 } Institute for Theoretical Physics and Astrophysics, University of Würzburg, Germany -\\ -\textbf{ 7 } University Library, Technische Universität Braunschweig, Germany -\\ -\textbf{ 8 } Jülich Supercomputing Centre, Forschungszentrum Jülich GmbH, Germany -\\ -\textbf{ 9 } Cluster of Excellence Matters of Activity. Image Space Material at Humboldt-Universität zu Berlin, Germany -\\ -\textbf{ 10 } Center for Computational and Theoretical Biology, University of Würzburg, Germany -\\ -\textbf{ 11 } Semantic Technologies team, ZB MED Information Centre for Life Sciences, Germany -\\ -\textbf{ 12 } German Climate Computing Center (DKRZ), Germany -\\ -\textbf{ 13 } Institute for Computational Physics, University of Stuttgart, Germany -\\ -\textbf{ 14 } Geschäftsbereich IT, Charité Universitätsmedizin Berlin, Germany -\\ -\textbf{ 15 } Institute of Biomedical Engineering, Karlsruhe Institute of Technology, Germany -\\ -\textbf{ 16 } Centre for Advanced Analytics and Predictive Sciences, University of Augsburg, Germany -\\ -\textbf{ 17 } Scientific IT Services, ETH Zurich, Switzerland -\\ -\textbf{ 18 } Institute of Carbon Cycles, Helmholtz Coastal Data Center, Helmholtz-Zentrum Hereon, Germany -\\ -\bigskip - -% Use the asterisk to denote corresponding authorship and provide email address in note below. -* dominic.kempf@iwr.uni-heidelberg.de +\input{contributors.tex} \end{flushleft} % Please keep the abstract below 300 words From 065c7e38feece9397e36a37a136e2539cd579027 Mon Sep 17 00:00:00 2001 From: Magnus Hagdorn Date: Wed, 27 Aug 2025 10:28:56 +0200 Subject: [PATCH 12/17] fix spelling in comments of plos template --- paper.tex | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/paper.tex b/paper.tex index d1e077e..3ea05b4 100644 --- a/paper.tex +++ b/paper.tex @@ -32,7 +32,7 @@ \usepackage[nopatch=eqnum]{microtype} \DisableLigatures[f]{encoding = *, family = * } -% color can be used to apply background shading to table cells only +% colour can be used to apply background shading to table cells only \usepackage[table]{xcolor} % array package and thick rules for tables @@ -127,7 +127,7 @@ % Title must be 250 characters or less. \begin{flushleft} {\Large -\textbf{Developing central Research Software Engineering units in German research institutions} % Please use "sentence case" for title and headings (capitalize only the first word in a title (or heading), the first word in a subtitle (or subheading), and any proper nouns). +\textbf{Developing central Research Software Engineering units in German research institutions} % Please use "sentence case" for title and headings (capitalise only the first word in a title (or heading), the first word in a subtitle (or subheading), and any proper nouns). } \newline % Insert author names, affiliations and corresponding author email (do not include titles, positions, or degrees). From 34df7bf6e597b7a8bb56f67762d8352c76bc206b Mon Sep 17 00:00:00 2001 From: Magnus Hagdorn Date: Wed, 27 Aug 2025 10:38:37 +0200 Subject: [PATCH 13/17] use make in CI/CD to build paper --- .github/workflows/paper.yml | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/.github/workflows/paper.yml b/.github/workflows/paper.yml index 96db12e..e15a9e5 100644 --- a/.github/workflows/paper.yml +++ b/.github/workflows/paper.yml @@ -21,16 +21,10 @@ jobs: run: pip install -r requirements.txt - name: Install LaTeX requirements for matplotlib - run: sudo apt update -y && sudo apt install -y texlive-latex-base texlive-latex-extra cm-super-minimal texlive-fonts-extra latexmk texlive-bibtex-extra biber texlive-lang-german + run: sudo apt update -y && sudo apt install -y build-essential texlive-latex-base texlive-latex-extra cm-super-minimal texlive-fonts-extra latexmk texlive-bibtex-extra biber texlive-lang-german - - name: Create contributor snippet - run: python contributors.py - - - name: Create group composition plot - run: cd group_composition_plot && ./create_paper_plots.sh && cd - - - name: Compile paper - run: latexmk -pdf --file-line-error --halt-on-error --interaction=nonstopmode --recorder paper.tex + run: make - name: move run: mkdir -p github_artifacts && mv ${{ env.DIR }}/*.pdf ./github_artifacts/ From a63c59f11f3bcf72fdbf61bfbbf4a838e467402e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frank=20L=C3=B6ffler?= Date: Mon, 1 Sep 2025 08:18:32 +0200 Subject: [PATCH 14/17] also remove paper.bbl, in clean target --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 35b4523..2951e3f 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ all: plots paper.pdf clean: latexmk -c - rm -f paper.pdf plos.bib norm.bib + rm -f paper.pdf paper.bbl plos.bib norm.bib paper.pdf: paper.tex positionpaper.bib contributors.tex plos.bib latexmk -pdflatex paper.tex From fa40a612ee2e372281bde0d187c97335904b47f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frank=20L=C3=B6ffler?= Date: Mon, 1 Sep 2025 08:45:42 +0200 Subject: [PATCH 15/17] enable orcid and ror links in plos template --- contributors_plos.tex.j2 | 4 ++-- paper.tex | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/contributors_plos.tex.j2 b/contributors_plos.tex.j2 index ea664cc..64f66ab 100644 --- a/contributors_plos.tex.j2 +++ b/contributors_plos.tex.j2 @@ -6,12 +6,12 @@ % Note: the zero-width character <200b> is in here on purpose (to not mess up authors without % affiliation) {%- for author in data.authors %} -{{ author.author }}​{% if author.affiliations %}\textsuperscript{{ "{" }}{{ author.affiliations|join(",") }}{% if author.corresponding_author is defined and author.corresponding_author %}*{% endif %}{{ "}" }}{% endif %} +{{ author.author }}​{% if author.affiliations %}\textsuperscript{{ "{" }}{{ author.affiliations|join(",") }}{% if author.corresponding_author is defined and author.corresponding_author %}*{% endif %}{% if author.orcid is defined %}\texorpdfstring{\thinspace\orcidlink{ {{-author.orcid-}} }}{}{% endif %}{{ "}" }}{% endif %} {%- endfor %} \\ \bigskip {%- for index, affiliation in data.affiliations.items() %} -\textbf{{ "{" }}{{ index }}{{ "}" }} {{ affiliation.name }} +\textbf{{ "{" }}{{ index }}{{ "}" }} {{ affiliation.name }}{% if affiliation.ror is defined %}\texorpdfstring{\thinspace\rorlink{ {{-affiliation.ror-}} }} {}{% endif %} \\ {%- endfor %} \bigskip diff --git a/paper.tex b/paper.tex index 3ea05b4..a7d4c2a 100644 --- a/paper.tex +++ b/paper.tex @@ -35,6 +35,9 @@ % colour can be used to apply background shading to table cells only \usepackage[table]{xcolor} +\usepackage{orcidlink} +\usepackage{rorlink} + % array package and thick rules for tables \usepackage{array} From da9edcb23f0818edaa13114111b4819ac8caa514 Mon Sep 17 00:00:00 2001 From: Dominic Kempf Date: Thu, 4 Sep 2025 13:59:47 +0200 Subject: [PATCH 16/17] Remove footnotes for PLOS --- paper.tex | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/paper.tex b/paper.tex index a7d4c2a..41c4d0b 100644 --- a/paper.tex +++ b/paper.tex @@ -249,13 +249,13 @@ \subsection*{Pooling: an already tested idea} \subsubsection*{Research data management} Both data and software play a fundamental role in almost all of research. -Over the past decades, Research Data Management (RDM) has evolved into a topic of national interest with NFDI\footnote{Nationale Forschungsdateninfrastruktur: the national research data infrastructure in Germany} consortia for all disciplines and a research data law. -Federal state RDM initiatives\footnote{\url{https://forschungsdaten.info/fdm-im-deutschsprachigen-raum/deutschland/}} have established the topic further and provide regional training, networking and other supporting services. +Over the past decades, Research Data Management (RDM) has evolved into a topic of national interest with NFDI (Nationale Forschungsdateninfrastruktur, the national research data infrastructure in Germany) consortia for all disciplines and a research data law. +Federal state RDM initiatives have established the topic further and provide regional training, networking and other supporting services. Many research organisations have set up established central RDM groups that support research projects in all aspects from grant proposals to hands-on support and maintaining Data Management Plans (DMPs). Funding agencies acknowledge the importance of research data and have started to make RDM mandatory in research projects. The most recent funding guidelines suggest to have “data stewards” in data-driven research. -Such experts are to be employed in advanced research projects like “Collaborative Research Centres” (CRC)\footnote{Sonderforschungsbereich (SFB)} or “Clusters of Excellence”\footnote{Cluster der Exzellenzinitiative}. +Such experts are to be employed in advanced research projects like the DFG funding lines “Collaborative Research Centres” (Sonderforschungsbereich) or “Clusters of Excellence”. These data experts support research projects in several aspects including DMPs, grant applications, data availability for journal publications, compliance, FAIRification and more. Similarly, central RSEs will encourage other RSEs to publish software with rich metadata and will support journal publications with code submission requirements. With the increasing recognition of software as a research product, it is easy to see how projects will require and benefit from support in research software management in the near future. @@ -302,7 +302,7 @@ \subsection*{External expectations} and the German Research Council~\cite{dfg_gsp}. Another development taking place worldwide is the encouragement of authors to submit both, data and software, for peer review. -As an example, the journal “Nature” initiated such a policy\footnote{\url{https://www.nature.com/nature-portfolio/editorial-policies/reporting-standards}} in 2018~\cite{Nature2018}. +As an example, the journal “Nature” initiated such a policy in 2018~\cite{Nature2018}. RSE groups are able to offer researchers consulting tailored to their specific needs on how to implement and document those policies. This is especially relevant in the context of reproducibility of software-based research. @@ -628,14 +628,14 @@ \subsubsection*{Initial Measures} Forming a network of RSEs localised at an institution can be initiated by any existing RSE individual or group that is preferably already in contact with other RSEs at the institution. An institutional dedicated mailing list, chat group, and possibly other communication platforms can be created and a request for participation can be circulated via institutional channels such as an employee newsletter. First common events such as social gatherings or RSE-related seminar talks can be organised and announced via the communication platform. -If the initiative is geographically local, this process can be accompanied, facilitated and strengthened by founding a local de-RSE chapter\footnote{A list of existing chapters: \url{https://de-rse.org/chapter/}.}. +If the initiative is geographically local, this process can be accompanied, facilitated and strengthened by founding a local de-RSE chapter (list of existing chapters: \url{https://de-rse.org/chapter/}). Such network-building has been successfully initiated and implemented at several German research institutions such as the German Aerospace Center and the Forchungszentrum Jülich. \paragraph{Pooling of existing teaching materials and training offers} Depending on local RSE efforts, teaching materials and associated training formats are likely to already exist, distributed over individual institutional groups. With the established network, the materials can be pooled and joint training can be offered to a wider institutional audience. -This step can be facilitated and formalised by offering introductory courses with a recognised curriculum as provided by The Carpentries\footnote{Carpentry examples: \url{https://software-carpentry.org/lessons/}} -or CodeRefinery\footnote{CodeRefinery examples: \url{https://coderefinery.org/lessons/}}. +This step can be facilitated and formalised by offering introductory courses with a recognised curriculum as provided by The Carpentries (see e.g. \url{https://software-carpentry.org/lessons/}) +or CodeRefinery (see e.g. \url{https://coderefinery.org/lessons/}). \subsubsection*{Developing a Business Plan} Decision processes at institutions usually require a business plan on which to base the decision on whether to establish an RSE unit. From 6b849b63e28903f1e161576514423f1f95800efe Mon Sep 17 00:00:00 2001 From: Dominic Kempf Date: Thu, 4 Sep 2025 14:11:00 +0200 Subject: [PATCH 17/17] Use nameref for PLOS, as they use unnumbered entities --- paper.tex | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/paper.tex b/paper.tex index a7d4c2a..366990d 100644 --- a/paper.tex +++ b/paper.tex @@ -358,7 +358,7 @@ \subsection*{Module 2: Consultation Services}% \label{sec:consultation} With the majority of researchers being self-taught programmers~\cite{Carver2013}, there is a huge demand for expertise on how to develop better research software. -Here, “better” can refer to a number of quality metrics as already mentioned in Section~\ref{sec:motivation}: correctness, reproducibility, maintainability, extensibility, usability, portability, interoperability, security, performance, or scalability~\cite[Chapter 16]{Schulmeyer2008}. +Here, “better” can refer to a number of quality metrics as already mentioned in Section~\nameref{sec:motivation}: correctness, reproducibility, maintainability, extensibility, usability, portability, interoperability, security, performance, or scalability~\cite[Chapter 16]{Schulmeyer2008}. In order to raise the quality standards for research that is based on research software, it is of great importance for research institutions to provide access to such expertise with a low barrier to entry. The hub is a natural place to provide this central service. @@ -545,7 +545,7 @@ \section*{Existing Implementations}% \begin{figure} \centering \includegraphics[width=.8\textwidth]{./group_composition_plot/group_composition_plot_the_fantastic_four.pdf} -\caption{National and international examples of RSE units and their service portfolio, structured by activities corresponding to the modules described in Section~\ref{sec:vision}. +\caption[Example service portfolios]{National and international examples of RSE units and their service portfolio, structured by activities corresponding to the modules described in Section~\nameref{sec:vision}. \protect\input{./group_composition_plot/group_composition_plot_the_fantastic_four.labels}\unskip. Heidelberg and Princeton offer development services, whereas Jena and Reading focus mostly on teaching and consultation services.}% \label{fig:survey} @@ -553,9 +553,9 @@ \section*{Existing Implementations}% A number of successful RSE units have already been established in Germany and many more exist in other countries, especially the UK and the US\@. In order to understand the service portfolio of these existing RSE units, we conducted a small survey that received a total of twelve responses from Germany, the UK and the US\@. -We asked RSE units for the composition of their service portfolio --- the results are shown in Figure~\ref{fig:survey}. +We asked RSE units for the composition of their service portfolio --- the results are shown in Figure~\nameref{fig:survey}. -From the gathered data and the additional free text information of the participants, we conclude that the service components that we have identified in Section~\ref{sec:vision} are indeed relevant for existing RSE units. +From the gathered data and the additional free text information of the participants, we conclude that the service components that we have identified in Section~\nameref{sec:vision} are indeed relevant for existing RSE units. Additionally, we see a large diversity in the weighting of these components, which is to be expected given the different environments of the RSE units. Within this diverse data set, we identified two rather different archetypes of RSE units: those that offer development services and those that do not. The RSE units offering development services would typically invest a lot of their resources into this component, whereas others put a much larger emphasis on teaching and consultation services. @@ -620,7 +620,7 @@ \subsection*{Transition Pathway} We conclude with measures for promoting its growth. \subsubsection*{Initial Measures} -The following measures initialise the two modules presented in \autoref{sec:network} and \autoref{sec:teaching}. +The following measures initialise the two modules presented in \nameref{sec:network} and \nameref{sec:teaching}. While dedicated funding certainly is beneficial already for this step, it is not strictly necessary. Once the two measures are in place, they can be used to illustrate the need for institutional RSE activities and therefore support funding proposals. @@ -639,7 +639,7 @@ \subsubsection*{Initial Measures} \subsubsection*{Developing a Business Plan} Decision processes at institutions usually require a business plan on which to base the decision on whether to establish an RSE unit. -The business plan should include an outline of the RSE unit, its responsibilities and offerings as a subset of the nine modules presented in \autoref{sec:vision}, the funding, and the resulting benefits for the institution and its researchers. +The business plan should include an outline of the RSE unit, its responsibilities and offerings as a subset of the nine modules presented in \nameref{sec:vision}, the funding, and the resulting benefits for the institution and its researchers. A crucial and sometimes difficult question is how to position the RSE unit within the institution’s organisational structure. A canonical place would be a new subunit of an existing unit close to software, training services and computing such as the local or central IT unit or the library. @@ -647,7 +647,7 @@ \subsubsection*{Developing a Business Plan} Another choice for the parent unit, particularly at universities, is the faculty for computer science. A key aspect for this decision is that the RSE unit must be able to work with all research groups at the institution, for which it needs to act independently and thus should not be absorbed by a larger unit. Since it offers a unique view on challenges related to research software, a smartly placed RSE unit is able to serve as link between the individual research groups and other central institutional units. -Therefore, determining the best place may involve discussions with several stakeholders at the institution and can already be beneficial for creating a network of institutional partners, see the module described in \autoref{sec:partners}. +Therefore, determining the best place may involve discussions with several stakeholders at the institution and can already be beneficial for creating a network of institutional partners, see the module described in \nameref{sec:partners}. The business plan also needs to address funding for the RSE unit's initial staff. We consider it necessary that there is a certain amount of base funding provided by the institution that covers a basic RSE unit because much RSE work is not project based. @@ -665,16 +665,16 @@ \subsubsection*{Establishing the Unit} The first position is an RSE coordinator who is the contact person for all embedded RSEs. Among other things, they are also responsible for organising meetings, developing training programs and reporting to stakeholders. The second position is a central RSE, responsible for providing selected services and infrastructure. -These core positions complement the network of RSEs as described in~\autoref{sec:network}. +These core positions complement the network of RSEs as described in~\nameref{sec:network}. -Drawing from the business plan and considering the initial staff situation, a first task of the centrally-funded structure is to define a basic service portfolio according to the modules described in \autoref{sec:vision}. -In addition to the aforementioned networking and teaching activities, see~\autoref{sec:network} and \autoref{sec:teaching}, it seems natural to start with consultation, see~\autoref{sec:consultation}, +Drawing from the business plan and considering the initial staff situation, a first task of the centrally-funded structure is to define a basic service portfolio according to the modules described in \nameref{sec:vision}. +In addition to the aforementioned networking and teaching activities, see~\nameref{sec:network} and \nameref{sec:teaching}, it seems natural to start with consultation, see~\nameref{sec:consultation}, as this allows to evaluate the potential necessities for other services such as development, infrastructure provisioning, and maintenance. An extension of the initial service portfolio for a larger target audience requires the acquisition of funding for further positions, see below. The best RSE unit can easily become useless if other departments as well as RSEs outside the central hub do not know about it. -Therefore, communication and outreach activities as described in~\autoref{sec:outreach}, particularly connecting to entities within the institution, is of utmost importance at this stage. +Therefore, communication and outreach activities as described in~\nameref{sec:outreach}, particularly connecting to entities within the institution, is of utmost importance at this stage. Although the inception of the RSE unit will be announced once the business plan has been approved by the institution, communication across the RSE hub, the RSE network and other departments should be done on a regular basis. Such a communication should facilitate collaboration among RSEs while also keeping non-RSEs in the loop. @@ -682,7 +682,7 @@ \subsubsection*{Establishing the Unit} \subsubsection*{Growth of the Unit} \paragraph{Acquisition of further funding} -The most promising possibilities to acquire further funding seem to be explicitly requesting person-months in externally funded projects and dedicated RSE calls, as discussed in \autoref{sec:funding}. +The most promising possibilities to acquire further funding seem to be explicitly requesting person-months in externally funded projects and dedicated RSE calls, as discussed in \nameref{sec:funding}. We believe that the credibility of a research proposal that is asking for RSE funds is greatly enhanced if the RSE unit is part of this proposal from the beginning. Over time, more and more researchers and proposals are expected to follow the institutional policy such that a consistent stream of income can be generated. @@ -692,7 +692,7 @@ \subsubsection*{Growth of the Unit} \end{mdframed} \paragraph{Offering of additional services} -With the additionally acquired funds, the service portfolio of the RSE unit can be enhanced regarding the modules described in \autoref{sec:vision}. +With the additionally acquired funds, the service portfolio of the RSE unit can be enhanced regarding the modules described in \nameref{sec:vision}. Obviously, the selection of modules and their share in the overall portfolio depend on the services that have been applied for in the corresponding proposals. As this is strongly connected to hiring persons with the required expertise, this has to be carefully planned, see also below.