| name | journal_formatting |
| description | Apply journal-specific formatting rules to transform a manuscript from Markdown |
Skill: Journal Formatting
Purpose
Apply journal-specific formatting rules to transform a manuscript from Markdown
into a submission-ready LaTeX or Word document.
When to Use
- Final formatting before submission
- Converting between journal formats (e.g., rejected → resubmit elsewhere)
- Checking manuscript compliance with journal guidelines
Scope: Journal Papers Only (Not Books)
This skill and the --journal profiles apply only to single-manuscript
journal papers built with the paperflow new / draft / format / render
pipeline (papers/). The journal latex_class and citation_style metadata
drive the paper renderer in tools/paper_renderer.py.
Books are a separate pipeline and do NOT use journal profiles. A book lives
under books/<slug>/, is configured by book.yaml (not a journal YAML), and is
produced by paperflow book-render --format {pdf|docx|html|epub|odf} via the
dedicated tools/book_render_* renderers:
| Format | Book renderer | Engine |
|---|
| PDF | book_render_pdf.py | Typst (auto-generated preamble) |
| Word | book_render_word.py | python-docx |
| HTML | book_render_html.py | custom HTML template |
| EPUB | book_render_epub.py | pandoc |
| ODF | book_render_odf.py | odfpy |
| JATS/DocBook | book_render_xml.py (via book-render-xml) | pandoc |
cmd_book_render never calls load_journal_profile, so --journal,
elsarticle/achemso classes, and the compliance checks below are irrelevant
to books. Style books through book.yaml and the book_render_* engines
instead. The shared building blocks between the two pipelines are bibliography
handling (refs.bib, Crossref enrichment) and the equation/figure utilities in
tools/math_utils.py — not the journal class machinery.
Supported Journals
Each journal has a YAML profile in journals/. Run
python paperflow.py list-journals to print this list with the exact
--journal names. Currently supported (10 profiles):
| Journal | --journal name | Publisher | LaTeX Class | Citation Style |
|---|
| Fluid Phase Equilibria | fluid_phase_equilibria | Elsevier | elsarticle | numbered |
| Chemical Engineering Science | chem_eng_sci | Elsevier | elsarticle | numbered |
| Computers & Chemical Engineering | computers_chem_eng | Elsevier | elsarticle | authoryear |
| Geoenergy Science and Engineering | geoenergy_sci_eng | Elsevier | elsarticle | numbered |
| Int. J. of Greenhouse Gas Control | ijggc | Elsevier | elsarticle | numbered |
| Industrial & Engineering Chemistry Research | iecr | ACS | achemso | numbered_superscript |
| Journal of Chemical & Engineering Data | jced | ACS | achemso | numbered_superscript |
| Energy & Fuels | energy_fuels | ACS | achemso | numbered_superscript |
| AIChE Journal | aiche | Wiley | custom | numbered |
| SPE Conference Paper | spe | SPE | custom | numbered |
The latex_class value drives how the LaTeX renderer
(tools/paper_renderer.py, render_latex) emits front matter — see the
class-specific sections below. The three supported citation_style values are
numbered (square-bracket [1]), numbered_superscript (ACS-style ¹), and
authoryear ((Author, Year)).
Elsevier Formatting (elsarticle)
LaTeX Class
\documentclass[review,3p,authoryear]{elsarticle}
% review = double-spaced with line numbers
% 3p = three-column proof style
% authoryear or number for citation style
Front Matter
\begin{frontmatter}
\title{Your Title Here}
\author[inst1]{First Author\corref{cor1}}
\cortext[cor1]{Corresponding author. Tel.: +47-xxx}
\ead{email@institution.no}
\author[inst1]{Second Author}
\author[inst2]{Third Author}
\affiliation[inst1]{organization={Department of Chemistry, NTNU},
city={Trondheim},
country={Norway}}
\affiliation[inst2]{organization={Equinor ASA},
city={Stavanger},
country={Norway}}
\begin{abstract}
% Check journal profile for abstract word limit (FPE: 250 words)
\end{abstract}
\begin{keyword}
flash calculation \sep phase equilibrium \sep equation of state \sep
successive substitution \sep Newton-Raphson \sep convergence
\end{keyword}
\begin{highlights}
\item Improved TP flash algorithm with adaptive SS-NR switching
\item Systematic benchmark across 1000+ cases and 6 fluid families
\item 15\% fewer iterations on average for multicomponent systems
\item Enhanced robustness for near-critical conditions
\item Open-source implementation in NeqSim
\end{highlights}
\end{frontmatter}
Reference Style
Elsevier numbered style:
\bibliographystyle{elsarticle-num}
\bibliography{refs}
Figure Inclusion
\begin{figure}[htbp]
\centering
\includegraphics[width=\textwidth]{figures/convergence_map.pdf}
\caption{Convergence success map in temperature-pressure space for
the lean gas family. Green dots indicate successful flash convergence;
red crosses indicate failure. The proposed algorithm (right) reduces
the failure region near the phase boundary.}
\label{fig:convergence_map}
\end{figure}
Table Style (Three-Line)
\begin{table}[htbp]
\centering
\caption{Benchmark results summary across all fluid families.
$N$ is the number of test cases, Conv.\ is the convergence rate,
Med.\ Iter.\ is the median iteration count for converged cases.}
\label{tab:results}
\begin{tabular}{lrcccc}
\toprule
Family & $N$ & \multicolumn{2}{c}{Conv.\ (\%)} & \multicolumn{2}{c}{Med.\ Iter.} \\
\cmidrule(lr){3-4} \cmidrule(lr){5-6}
& & Base & Cand. & Base & Cand. \\
\midrule
Lean gas & 200 & 100.0 & 100.0 & 6 & 5 \\
Rich gas & 200 & 99.0 & 99.5 & 8 & 7 \\
Gas condensate & 200 & 95.0 & 98.0 & 14 & 11 \\
CO2-rich & 200 & 97.5 & 98.5 & 10 & 9 \\
Wide-boiling & 100 & 93.0 & 96.0 & 18 & 14 \\
Near-critical & 100 & 85.0 & 92.0 & 22 & 16 \\
\midrule
\textbf{All} & \textbf{1000} & \textbf{95.8} & \textbf{98.2} & \textbf{10} & \textbf{8} \\
\bottomrule
\end{tabular}
\end{table}
ACS Formatting (achemso)
ACS journals (iecr, jced, energy_fuels) use the achemso document class.
Unlike elsarticle, achemso declares authors, affiliations, and the title in
the preamble — before \begin{document} — and has no frontmatter or
highlights environment. The renderer emits this automatically based on
latex_class: achemso.
LaTeX Class
\documentclass{achemso}
% achemso auto-detects the journal style from \journal{} when set; the
% journal profiles deliberately set `latex_options: null` so no class options
% are injected (the renderer omits the [] brackets entirely).
Preamble (before \begin{document})
\author{First Author}
\affiliation{Department of Chemistry, NTNU, Trondheim, Norway}
\author{Second Author}
\affiliation{Equinor ASA, Stavanger, Norway}
\email{corresponding@institution.no} % only for the corresponding author
\title{Your Title Here}
\begin{document}
Body front matter (after \begin{document})
\begin{abstract}
% Check journal profile for the abstract word limit
\end{abstract}
\keywords{flash calculation; phase equilibrium; equation of state}
Citations and References
ACS journals use superscript numbered citations
(citation_style: numbered_superscript):
\bibliographystyle{achemso}
\bibliography{refs}
Highlights: achemso has no highlights environment. When a profile sets
highlights_required: true, the renderer preserves the highlight text as a
LaTeX comment block so no content is lost, but it does not appear in the
compiled PDF. Move highlight content into the abstract for ACS submissions.
Custom / Generic Formatting (custom)
aiche (Wiley) and spe (SPE) set latex_class: custom because the publisher
supplies its own class file. The renderer falls back to a generic
\maketitle front matter that compiles with the standard article class as a
preview, then you drop in the publisher template for the real submission.
\documentclass{custom} % swap for the publisher-provided class
\begin{document}
\title{Your Title Here}
\author{First Author \and Second Author}
\maketitle
\begin{abstract}
% ...
\end{abstract}
\noindent\textbf{Keywords:} keyword one, keyword two, keyword three
Both custom journals use citation_style: numbered. Replace the generic
preamble with the publisher's macros (Wiley \corraddress, SPE template fields)
before final submission.
Compliance Checklist Generator
def check_compliance(manuscript, journal_profile):
"""Check manuscript against journal requirements."""
checks = []
abstract = extract_abstract(manuscript)
word_count = len(abstract.split())
max_words = journal_profile["abstract_words_max"]
checks.append({
"check": "Abstract length",
"status": "PASS" if word_count <= max_words else "FAIL",
"detail": f"{word_count}/{max_words} words"
})
keywords = extract_keywords(manuscript)
max_kw = journal_profile["keywords_max"]
checks.append({
"check": "Keywords count",
"status": "PASS" if len(keywords) <= max_kw else "FAIL",
"detail": f"{len(keywords)}/{max_kw} keywords"
})
if journal_profile.get("highlights_required"):
highlights = extract_highlights(manuscript)
checks.append({
"check": "Highlights present",
"status": "PASS" if highlights else "FAIL",
"detail": f"{(highlights)} highlights"
})
i, h (highlights):
max_chars = journal_profile[]
checks.append({
: ,
: (h) <= max_chars ,
:
})
journal_profile.get():
has_da = manuscript.lower()
checks.append({
: ,
: has_da
})
checks
Cross-Journal Conversion
When a paper is rejected and needs to be resubmitted elsewhere:
- Read the new journal's YAML profile
- Adjust section order if different
- Change citation style
- Update abstract length if needed
- Add/remove highlights
- Update LaTeX class and options
- Re-run compliance check
Common Gotchas
| Issue | Solution |
|---|
| Abstract too long for target journal | Shorten, keep key numbers |
| Wrong citation style | Change \bibliographystyle{} |
| Double spacing not applied | Add \usepackage{setspace}\doublespacing |
| Line numbers missing | Add \usepackage{lineno}\linenumbers |
| Figures wrong format | Convert PNG → PDF/EPS |
| Highlights missing | Extract from abstract/conclusions |
| CRediT statement missing | Add to acknowledgements |
Word Document Generation
Overview
The word_renderer.py tool in tools/ generates publication-quality Word
documents from paper.md. It is called automatically by paperflow format.
Native OMML Equations (Primary Pipeline)
Word documents use native Office Math (OMML) equations — the same editing
experience as typing in Word's equation editor. The pipeline is:
LaTeX string → latex2mathml → MathML XML → XSLT (MML2OMML.XSL) → OMML element → Word paragraph
Requirements:
- Python packages:
latex2mathml, lxml, python-docx
- XSL file:
MML2OMML.XSL (ships with Microsoft Office 2013+, typically at
%ProgramFiles%\Microsoft Office\root\Office16\MML2OMML.XSL)
Fallback: If OMML pipeline is unavailable, equations render as Unicode text
(Greek letters, operators) — readable but not editable as math objects.
Reusable Helpers for Per-Paper build_word.py
Per-paper build_word.py scripts MUST reuse the shared helpers in
tools/math_utils.py rather than flattening LaTeX to plain text (which renders
poorly in Word — literal ^, _, and (a)/(b) fractions):
import sys
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parents[2] / "tools"))
import math_utils
p = math_utils.add_display_equation(doc, eq_text, size=11)
math_utils.append_inline_math(paragraph, latex, size=10.5)
Both helpers automatically fall back to a Unicode text run when the OMML
toolchain (latex2mathml + MML2OMML.XSL) is unavailable, so builds stay robust
on CI and machines without Microsoft Office.
Word Rendering Features
| Feature | Implementation |
|---|
Inline math $...$ | OMML elements embedded in paragraph runs |
Display equations $$...$$ | Centered OMML with sequential (N) numbering |
| Tables | Booktabs style: top/bottom 1.5pt borders, thin inside-H, blue header fill, no vertical rules |
| Figures | Embedded PNG with numbered "Figure N." caption |
Citations \cite{key} | Resolved to [N] from refs.bib (alphabetical order) |
| Code blocks | Shaded single-cell table in Consolas 8.5pt |
| Bold/italic/code | Inline formatting via **, *, backtick |
| Page numbers | Footer field (auto-incrementing PAGE) |
| Highlights | Bulleted list with filled circles |
| Abstract | Slightly indented, 1.5× line spacing |
| References | Hanging indent [N] Author (year). Title. Journal. |
Journal Profile Integration
The Word renderer reads journal profile YAML values:
double_spacing_required: true
line_spacing: 2.0
These override the renderer defaults (font sizes, margins, spacing).
API Usage
from word_renderer import render_word_document
render_word_document("papers/my_paper/")
import yaml
with open("journals/computers_chem_eng.yaml") as f:
profile = yaml.safe_load(f)
render_word_document("papers/my_paper/", journal_profile=profile)
render_word_document("papers/my_paper/", output_dir="output/")
How It Works Internally
- Setup: Creates Word document with page layout, styles, footer
- Parse: Splits
paper.md into sections by # headings
- Front matter: Title → Author placeholder → Highlights → Abstract → Keywords
- Body: For each section:
- Display equations (
$$...$$) → centered OMML + equation number
- Tables (pipe syntax) → booktabs-style Word table
- Images (
) → embedded figure with caption
- Code blocks → shaded table cell
- Lists → bulleted or numbered paragraphs
- Text → paragraph with inline math/bold/italic/code
- References: Parsed from
refs.bib, numbered alphabetically
- Save: Writes to
submission/paper.docx (uses timestamped name if locked)
Limitations
- Does not support line numbering (Word limitation in python-docx)
- No automatic cross-references (
\ref{fig:X} not resolved)
- BibTeX parsing is regex-based (covers standard entry types)
- Complex nested LaTeX (e.g.,
\frac{\frac{a}{b}}{c}) may need manual cleanup
Pre-Submission Quality Tools
Run these CLI commands before generating submission files:
python paperflow.py validate-figures papers/<slug>/ --journal <journal_name>
python paperflow.py validate-bib papers/<slug>/
python paperflow.py check-prose papers/<slug>/
python paperflow.py suggest-refs papers/<slug>/ --max 10
python paperflow.py diff papers/<slug>/
All [!!] (fail) items from validate-figures and validate-bib must be
resolved before formatting. check-prose and suggest-refs are advisory.