Assignment Operators

Add and assign, subtract and assign, multiply and assign, divide and assign, floor divide and assign, exponent and assign, modulo and assign.

For demonstration purposes, let’s use a single variable, num . Initially, we set num to 6. We can apply all of these operators to num and update it accordingly.

Assigning the value of 6 to num results in num being 6.

Expression: num = 6

Adding 3 to num and assigning the result back to num would result in 9.

Expression: num += 3

Subtracting 3 from num and assigning the result back to num would result in 6.

Expression: num -= 3

Multiplying num by 3 and assigning the result back to num would result in 18.

Expression: num *= 3

Dividing num by 3 and assigning the result back to num would result in 6.0 (always a float).

Expression: num /= 3

Performing floor division on num by 3 and assigning the result back to num would result in 2.

Expression: num //= 3

Raising num to the power of 3 and assigning the result back to num would result in 216.

Expression: num **= 3

Calculating the remainder when num is divided by 3 and assigning the result back to num would result in 2.

Expression: num %= 3

We can effectively put this into Python code, and you can experiment with the code yourself! Click the “Run” button to see the output.

The above code is useful when we want to update the same number. We can also use two different numbers and use the assignment operators to apply them on two different values.

Python Operators: Arithmetic, Assignment, Comparison, Logical, Identity, Membership, Bitwise

Operators are special symbols that perform some operation on operands and returns the result. For example, 5 + 6 is an expression where + is an operator that performs arithmetic add operation on numeric left operand 5 and the right side operand 6 and returns a sum of two operands as a result.

Python includes the operator module that includes underlying methods for each operator. For example, the + operator calls the operator.add(a,b) method.

Above, expression 5 + 6 is equivalent to the expression operator.add(5, 6) and operator.__add__(5, 6) . Many function names are those used for special methods, without the double underscores (dunder methods). For backward compatibility, many of these have functions with the double underscores kept.

Python includes the following categories of operators:

Arithmetic Operators

Assignment operators, comparison operators, logical operators, identity operators, membership test operators, bitwise operators.

Arithmetic operators perform the common mathematical operation on the numeric operands.

The arithmetic operators return the type of result depends on the type of operands, as below.

  • If either operand is a complex number, the result is converted to complex;
  • If either operand is a floating point number, the result is converted to floating point;
  • If both operands are integers, then the result is an integer and no conversion is needed.

The following table lists all the arithmetic operators in Python:

The assignment operators are used to assign values to variables. The following table lists all the arithmetic operators in Python:

The comparison operators compare two operands and return a boolean either True or False. The following table lists comparison operators in Python.

The logical operators are used to combine two boolean expressions. The logical operations are generally applicable to all objects, and support truth tests, identity tests, and boolean operations.

The identity operators check whether the two objects have the same id value e.i. both the objects point to the same memory location.

The membership test operators in and not in test whether the sequence has a given item or not. For the string and bytes types, x in y is True if and only if x is a substring of y .

Bitwise operators perform operations on binary operands.

  • Compare strings in Python
  • Convert file data to list
  • Convert User Input to a Number
  • Convert String to Datetime in Python
  • How to call external commands in Python?
  • How to count the occurrences of a list item?
  • How to flatten list in Python?
  • How to merge dictionaries in Python?
  • How to pass value by reference in Python?
  • Remove duplicate items from list in Python
  • More Python articles

and assignment operator in python

We are a team of passionate developers, educators, and technology enthusiasts who, with their combined expertise and experience, create in -depth, comprehensive, and easy to understand tutorials.We focus on a blend of theoretical explanations and practical examples to encourages hands - on learning. Visit About Us page for more information.

  • Python Questions & Answers
  • Python Skill Test
  • Python Latest Articles

logo

Python Numerical Methods

../_images/book_cover.jpg

This notebook contains an excerpt from the Python Programming and Numerical Methods - A Guide for Engineers and Scientists , the content is also available at Berkeley Python Numerical Methods .

The copyright of the book belongs to Elsevier. We also have this interactive book online for a better learning experience. The code is released under the MIT license . If you find this content useful, please consider supporting the work on Elsevier or Amazon !

< 2.0 Variables and Basic Data Structures | Contents | 2.2 Data Structure - Strings >

Variables and Assignment ¶

When programming, it is useful to be able to store information in variables. A variable is a string of characters and numbers associated with a piece of information. The assignment operator , denoted by the “=” symbol, is the operator that is used to assign values to variables in Python. The line x=1 takes the known value, 1, and assigns that value to the variable with name “x”. After executing this line, this number will be stored into this variable. Until the value is changed or the variable deleted, the character x behaves like the value 1.

TRY IT! Assign the value 2 to the variable y. Multiply y by 3 to show that it behaves like the value 2.

A variable is more like a container to store the data in the computer’s memory, the name of the variable tells the computer where to find this value in the memory. For now, it is sufficient to know that the notebook has its own memory space to store all the variables in the notebook. As a result of the previous example, you will see the variable “x” and “y” in the memory. You can view a list of all the variables in the notebook using the magic command %whos .

TRY IT! List all the variables in this notebook

Note that the equal sign in programming is not the same as a truth statement in mathematics. In math, the statement x = 2 declares the universal truth within the given framework, x is 2 . In programming, the statement x=2 means a known value is being associated with a variable name, store 2 in x. Although it is perfectly valid to say 1 = x in mathematics, assignments in Python always go left : meaning the value to the right of the equal sign is assigned to the variable on the left of the equal sign. Therefore, 1=x will generate an error in Python. The assignment operator is always last in the order of operations relative to mathematical, logical, and comparison operators.

TRY IT! The mathematical statement x=x+1 has no solution for any value of x . In programming, if we initialize the value of x to be 1, then the statement makes perfect sense. It means, “Add x and 1, which is 2, then assign that value to the variable x”. Note that this operation overwrites the previous value stored in x .

There are some restrictions on the names variables can take. Variables can only contain alphanumeric characters (letters and numbers) as well as underscores. However, the first character of a variable name must be a letter or underscores. Spaces within a variable name are not permitted, and the variable names are case-sensitive (e.g., x and X will be considered different variables).

TIP! Unlike in pure mathematics, variables in programming almost always represent something tangible. It may be the distance between two points in space or the number of rabbits in a population. Therefore, as your code becomes increasingly complicated, it is very important that your variables carry a name that can easily be associated with what they represent. For example, the distance between two points in space is better represented by the variable dist than x , and the number of rabbits in a population is better represented by nRabbits than y .

Note that when a variable is assigned, it has no memory of how it was assigned. That is, if the value of a variable, y , is constructed from other variables, like x , reassigning the value of x will not change the value of y .

EXAMPLE: What value will y have after the following lines of code are executed?

WARNING! You can overwrite variables or functions that have been stored in Python. For example, the command help = 2 will store the value 2 in the variable with name help . After this assignment help will behave like the value 2 instead of the function help . Therefore, you should always be careful not to give your variables the same name as built-in functions or values.

TIP! Now that you know how to assign variables, it is important that you learn to never leave unassigned commands. An unassigned command is an operation that has a result, but that result is not assigned to a variable. For example, you should never use 2+2 . You should instead assign it to some variable x=2+2 . This allows you to “hold on” to the results of previous commands and will make your interaction with Python must less confusing.

You can clear a variable from the notebook using the del function. Typing del x will clear the variable x from the workspace. If you want to remove all the variables in the notebook, you can use the magic command %reset .

In mathematics, variables are usually associated with unknown numbers; in programming, variables are associated with a value of a certain type. There are many data types that can be assigned to variables. A data type is a classification of the type of information that is being stored in a variable. The basic data types that you will utilize throughout this book are boolean, int, float, string, list, tuple, dictionary, set. A formal description of these data types is given in the following sections.

Python Enhancement Proposals

  • Python »
  • PEP Index »

PEP 572 – Assignment Expressions

The importance of real code, exceptional cases, scope of the target, relative precedence of :=, change to evaluation order, differences between assignment expressions and assignment statements, specification changes during implementation, _pydecimal.py, datetime.py, sysconfig.py, simplifying list comprehensions, capturing condition values, changing the scope rules for comprehensions, alternative spellings, special-casing conditional statements, special-casing comprehensions, lowering operator precedence, allowing commas to the right, always requiring parentheses, why not just turn existing assignment into an expression, with assignment expressions, why bother with assignment statements, why not use a sublocal scope and prevent namespace pollution, style guide recommendations, acknowledgements, a numeric example, appendix b: rough code translations for comprehensions, appendix c: no changes to scope semantics.

This is a proposal for creating a way to assign to variables within an expression using the notation NAME := expr .

As part of this change, there is also an update to dictionary comprehension evaluation order to ensure key expressions are executed before value expressions (allowing the key to be bound to a name and then re-used as part of calculating the corresponding value).

During discussion of this PEP, the operator became informally known as “the walrus operator”. The construct’s formal name is “Assignment Expressions” (as per the PEP title), but they may also be referred to as “Named Expressions” (e.g. the CPython reference implementation uses that name internally).

Naming the result of an expression is an important part of programming, allowing a descriptive name to be used in place of a longer expression, and permitting reuse. Currently, this feature is available only in statement form, making it unavailable in list comprehensions and other expression contexts.

Additionally, naming sub-parts of a large expression can assist an interactive debugger, providing useful display hooks and partial results. Without a way to capture sub-expressions inline, this would require refactoring of the original code; with assignment expressions, this merely requires the insertion of a few name := markers. Removing the need to refactor reduces the likelihood that the code be inadvertently changed as part of debugging (a common cause of Heisenbugs), and is easier to dictate to another programmer.

During the development of this PEP many people (supporters and critics both) have had a tendency to focus on toy examples on the one hand, and on overly complex examples on the other.

The danger of toy examples is twofold: they are often too abstract to make anyone go “ooh, that’s compelling”, and they are easily refuted with “I would never write it that way anyway”.

The danger of overly complex examples is that they provide a convenient strawman for critics of the proposal to shoot down (“that’s obfuscated”).

Yet there is some use for both extremely simple and extremely complex examples: they are helpful to clarify the intended semantics. Therefore, there will be some of each below.

However, in order to be compelling , examples should be rooted in real code, i.e. code that was written without any thought of this PEP, as part of a useful application, however large or small. Tim Peters has been extremely helpful by going over his own personal code repository and picking examples of code he had written that (in his view) would have been clearer if rewritten with (sparing) use of assignment expressions. His conclusion: the current proposal would have allowed a modest but clear improvement in quite a few bits of code.

Another use of real code is to observe indirectly how much value programmers place on compactness. Guido van Rossum searched through a Dropbox code base and discovered some evidence that programmers value writing fewer lines over shorter lines.

Case in point: Guido found several examples where a programmer repeated a subexpression, slowing down the program, in order to save one line of code, e.g. instead of writing:

they would write:

Another example illustrates that programmers sometimes do more work to save an extra level of indentation:

This code tries to match pattern2 even if pattern1 has a match (in which case the match on pattern2 is never used). The more efficient rewrite would have been:

Syntax and semantics

In most contexts where arbitrary Python expressions can be used, a named expression can appear. This is of the form NAME := expr where expr is any valid Python expression other than an unparenthesized tuple, and NAME is an identifier.

The value of such a named expression is the same as the incorporated expression, with the additional side-effect that the target is assigned that value:

There are a few places where assignment expressions are not allowed, in order to avoid ambiguities or user confusion:

This rule is included to simplify the choice for the user between an assignment statement and an assignment expression – there is no syntactic position where both are valid.

Again, this rule is included to avoid two visually similar ways of saying the same thing.

This rule is included to disallow excessively confusing code, and because parsing keyword arguments is complex enough already.

This rule is included to discourage side effects in a position whose exact semantics are already confusing to many users (cf. the common style recommendation against mutable default values), and also to echo the similar prohibition in calls (the previous bullet).

The reasoning here is similar to the two previous cases; this ungrouped assortment of symbols and operators composed of : and = is hard to read correctly.

This allows lambda to always bind less tightly than := ; having a name binding at the top level inside a lambda function is unlikely to be of value, as there is no way to make use of it. In cases where the name will be used more than once, the expression is likely to need parenthesizing anyway, so this prohibition will rarely affect code.

This shows that what looks like an assignment operator in an f-string is not always an assignment operator. The f-string parser uses : to indicate formatting options. To preserve backwards compatibility, assignment operator usage inside of f-strings must be parenthesized. As noted above, this usage of the assignment operator is not recommended.

An assignment expression does not introduce a new scope. In most cases the scope in which the target will be bound is self-explanatory: it is the current scope. If this scope contains a nonlocal or global declaration for the target, the assignment expression honors that. A lambda (being an explicit, if anonymous, function definition) counts as a scope for this purpose.

There is one special case: an assignment expression occurring in a list, set or dict comprehension or in a generator expression (below collectively referred to as “comprehensions”) binds the target in the containing scope, honoring a nonlocal or global declaration for the target in that scope, if one exists. For the purpose of this rule the containing scope of a nested comprehension is the scope that contains the outermost comprehension. A lambda counts as a containing scope.

The motivation for this special case is twofold. First, it allows us to conveniently capture a “witness” for an any() expression, or a counterexample for all() , for example:

Second, it allows a compact way of updating mutable state from a comprehension, for example:

However, an assignment expression target name cannot be the same as a for -target name appearing in any comprehension containing the assignment expression. The latter names are local to the comprehension in which they appear, so it would be contradictory for a contained use of the same name to refer to the scope containing the outermost comprehension instead.

For example, [i := i+1 for i in range(5)] is invalid: the for i part establishes that i is local to the comprehension, but the i := part insists that i is not local to the comprehension. The same reason makes these examples invalid too:

While it’s technically possible to assign consistent semantics to these cases, it’s difficult to determine whether those semantics actually make sense in the absence of real use cases. Accordingly, the reference implementation [1] will ensure that such cases raise SyntaxError , rather than executing with implementation defined behaviour.

This restriction applies even if the assignment expression is never executed:

For the comprehension body (the part before the first “for” keyword) and the filter expression (the part after “if” and before any nested “for”), this restriction applies solely to target names that are also used as iteration variables in the comprehension. Lambda expressions appearing in these positions introduce a new explicit function scope, and hence may use assignment expressions with no additional restrictions.

Due to design constraints in the reference implementation (the symbol table analyser cannot easily detect when names are re-used between the leftmost comprehension iterable expression and the rest of the comprehension), named expressions are disallowed entirely as part of comprehension iterable expressions (the part after each “in”, and before any subsequent “if” or “for” keyword):

A further exception applies when an assignment expression occurs in a comprehension whose containing scope is a class scope. If the rules above were to result in the target being assigned in that class’s scope, the assignment expression is expressly invalid. This case also raises SyntaxError :

(The reason for the latter exception is the implicit function scope created for comprehensions – there is currently no runtime mechanism for a function to refer to a variable in the containing class scope, and we do not want to add such a mechanism. If this issue ever gets resolved this special case may be removed from the specification of assignment expressions. Note that the problem already exists for using a variable defined in the class scope from a comprehension.)

See Appendix B for some examples of how the rules for targets in comprehensions translate to equivalent code.

The := operator groups more tightly than a comma in all syntactic positions where it is legal, but less tightly than all other operators, including or , and , not , and conditional expressions ( A if C else B ). As follows from section “Exceptional cases” above, it is never allowed at the same level as = . In case a different grouping is desired, parentheses should be used.

The := operator may be used directly in a positional function call argument; however it is invalid directly in a keyword argument.

Some examples to clarify what’s technically valid or invalid:

Most of the “valid” examples above are not recommended, since human readers of Python source code who are quickly glancing at some code may miss the distinction. But simple cases are not objectionable:

This PEP recommends always putting spaces around := , similar to PEP 8 ’s recommendation for = when used for assignment, whereas the latter disallows spaces around = used for keyword arguments.)

In order to have precisely defined semantics, the proposal requires evaluation order to be well-defined. This is technically not a new requirement, as function calls may already have side effects. Python already has a rule that subexpressions are generally evaluated from left to right. However, assignment expressions make these side effects more visible, and we propose a single change to the current evaluation order:

  • In a dict comprehension {X: Y for ...} , Y is currently evaluated before X . We propose to change this so that X is evaluated before Y . (In a dict display like {X: Y} this is already the case, and also in dict((X, Y) for ...) which should clearly be equivalent to the dict comprehension.)

Most importantly, since := is an expression, it can be used in contexts where statements are illegal, including lambda functions and comprehensions.

Conversely, assignment expressions don’t support the advanced features found in assignment statements:

  • Multiple targets are not directly supported: x = y = z = 0 # Equivalent: (z := (y := (x := 0)))
  • Single assignment targets other than a single NAME are not supported: # No equivalent a [ i ] = x self . rest = []
  • Priority around commas is different: x = 1 , 2 # Sets x to (1, 2) ( x := 1 , 2 ) # Sets x to 1
  • Iterable packing and unpacking (both regular or extended forms) are not supported: # Equivalent needs extra parentheses loc = x , y # Use (loc := (x, y)) info = name , phone , * rest # Use (info := (name, phone, *rest)) # No equivalent px , py , pz = position name , phone , email , * other_info = contact
  • Inline type annotations are not supported: # Closest equivalent is "p: Optional[int]" as a separate declaration p : Optional [ int ] = None
  • Augmented assignment is not supported: total += tax # Equivalent: (total := total + tax)

The following changes have been made based on implementation experience and additional review after the PEP was first accepted and before Python 3.8 was released:

  • for consistency with other similar exceptions, and to avoid locking in an exception name that is not necessarily going to improve clarity for end users, the originally proposed TargetScopeError subclass of SyntaxError was dropped in favour of just raising SyntaxError directly. [3]
  • due to a limitation in CPython’s symbol table analysis process, the reference implementation raises SyntaxError for all uses of named expressions inside comprehension iterable expressions, rather than only raising them when the named expression target conflicts with one of the iteration variables in the comprehension. This could be revisited given sufficiently compelling examples, but the extra complexity needed to implement the more selective restriction doesn’t seem worthwhile for purely hypothetical use cases.

Examples from the Python standard library

env_base is only used on these lines, putting its assignment on the if moves it as the “header” of the block.

  • Current: env_base = os . environ . get ( "PYTHONUSERBASE" , None ) if env_base : return env_base
  • Improved: if env_base := os . environ . get ( "PYTHONUSERBASE" , None ): return env_base

Avoid nested if and remove one indentation level.

  • Current: if self . _is_special : ans = self . _check_nans ( context = context ) if ans : return ans
  • Improved: if self . _is_special and ( ans := self . _check_nans ( context = context )): return ans

Code looks more regular and avoid multiple nested if. (See Appendix A for the origin of this example.)

  • Current: reductor = dispatch_table . get ( cls ) if reductor : rv = reductor ( x ) else : reductor = getattr ( x , "__reduce_ex__" , None ) if reductor : rv = reductor ( 4 ) else : reductor = getattr ( x , "__reduce__" , None ) if reductor : rv = reductor () else : raise Error ( "un(deep)copyable object of type %s " % cls )
  • Improved: if reductor := dispatch_table . get ( cls ): rv = reductor ( x ) elif reductor := getattr ( x , "__reduce_ex__" , None ): rv = reductor ( 4 ) elif reductor := getattr ( x , "__reduce__" , None ): rv = reductor () else : raise Error ( "un(deep)copyable object of type %s " % cls )

tz is only used for s += tz , moving its assignment inside the if helps to show its scope.

  • Current: s = _format_time ( self . _hour , self . _minute , self . _second , self . _microsecond , timespec ) tz = self . _tzstr () if tz : s += tz return s
  • Improved: s = _format_time ( self . _hour , self . _minute , self . _second , self . _microsecond , timespec ) if tz := self . _tzstr (): s += tz return s

Calling fp.readline() in the while condition and calling .match() on the if lines make the code more compact without making it harder to understand.

  • Current: while True : line = fp . readline () if not line : break m = define_rx . match ( line ) if m : n , v = m . group ( 1 , 2 ) try : v = int ( v ) except ValueError : pass vars [ n ] = v else : m = undef_rx . match ( line ) if m : vars [ m . group ( 1 )] = 0
  • Improved: while line := fp . readline (): if m := define_rx . match ( line ): n , v = m . group ( 1 , 2 ) try : v = int ( v ) except ValueError : pass vars [ n ] = v elif m := undef_rx . match ( line ): vars [ m . group ( 1 )] = 0

A list comprehension can map and filter efficiently by capturing the condition:

Similarly, a subexpression can be reused within the main expression, by giving it a name on first use:

Note that in both cases the variable y is bound in the containing scope (i.e. at the same level as results or stuff ).

Assignment expressions can be used to good effect in the header of an if or while statement:

Particularly with the while loop, this can remove the need to have an infinite loop, an assignment, and a condition. It also creates a smooth parallel between a loop which simply uses a function call as its condition, and one which uses that as its condition but also uses the actual value.

An example from the low-level UNIX world:

Rejected alternative proposals

Proposals broadly similar to this one have come up frequently on python-ideas. Below are a number of alternative syntaxes, some of them specific to comprehensions, which have been rejected in favour of the one given above.

A previous version of this PEP proposed subtle changes to the scope rules for comprehensions, to make them more usable in class scope and to unify the scope of the “outermost iterable” and the rest of the comprehension. However, this part of the proposal would have caused backwards incompatibilities, and has been withdrawn so the PEP can focus on assignment expressions.

Broadly the same semantics as the current proposal, but spelled differently.

Since EXPR as NAME already has meaning in import , except and with statements (with different semantics), this would create unnecessary confusion or require special-casing (e.g. to forbid assignment within the headers of these statements).

(Note that with EXPR as VAR does not simply assign the value of EXPR to VAR – it calls EXPR.__enter__() and assigns the result of that to VAR .)

Additional reasons to prefer := over this spelling include:

  • In if f(x) as y the assignment target doesn’t jump out at you – it just reads like if f x blah blah and it is too similar visually to if f(x) and y .
  • import foo as bar
  • except Exc as var
  • with ctxmgr() as var

To the contrary, the assignment expression does not belong to the if or while that starts the line, and we intentionally allow assignment expressions in other contexts as well.

  • NAME = EXPR
  • if NAME := EXPR

reinforces the visual recognition of assignment expressions.

This syntax is inspired by languages such as R and Haskell, and some programmable calculators. (Note that a left-facing arrow y <- f(x) is not possible in Python, as it would be interpreted as less-than and unary minus.) This syntax has a slight advantage over ‘as’ in that it does not conflict with with , except and import , but otherwise is equivalent. But it is entirely unrelated to Python’s other use of -> (function return type annotations), and compared to := (which dates back to Algol-58) it has a much weaker tradition.

This has the advantage that leaked usage can be readily detected, removing some forms of syntactic ambiguity. However, this would be the only place in Python where a variable’s scope is encoded into its name, making refactoring harder.

Execution order is inverted (the indented body is performed first, followed by the “header”). This requires a new keyword, unless an existing keyword is repurposed (most likely with: ). See PEP 3150 for prior discussion on this subject (with the proposed keyword being given: ).

This syntax has fewer conflicts than as does (conflicting only with the raise Exc from Exc notation), but is otherwise comparable to it. Instead of paralleling with expr as target: (which can be useful but can also be confusing), this has no parallels, but is evocative.

One of the most popular use-cases is if and while statements. Instead of a more general solution, this proposal enhances the syntax of these two statements to add a means of capturing the compared value:

This works beautifully if and ONLY if the desired condition is based on the truthiness of the captured value. It is thus effective for specific use-cases (regex matches, socket reads that return '' when done), and completely useless in more complicated cases (e.g. where the condition is f(x) < 0 and you want to capture the value of f(x) ). It also has no benefit to list comprehensions.

Advantages: No syntactic ambiguities. Disadvantages: Answers only a fraction of possible use-cases, even in if / while statements.

Another common use-case is comprehensions (list/set/dict, and genexps). As above, proposals have been made for comprehension-specific solutions.

This brings the subexpression to a location in between the ‘for’ loop and the expression. It introduces an additional language keyword, which creates conflicts. Of the three, where reads the most cleanly, but also has the greatest potential for conflict (e.g. SQLAlchemy and numpy have where methods, as does tkinter.dnd.Icon in the standard library).

As above, but reusing the with keyword. Doesn’t read too badly, and needs no additional language keyword. Is restricted to comprehensions, though, and cannot as easily be transformed into “longhand” for-loop syntax. Has the C problem that an equals sign in an expression can now create a name binding, rather than performing a comparison. Would raise the question of why “with NAME = EXPR:” cannot be used as a statement on its own.

As per option 2, but using as rather than an equals sign. Aligns syntactically with other uses of as for name binding, but a simple transformation to for-loop longhand would create drastically different semantics; the meaning of with inside a comprehension would be completely different from the meaning as a stand-alone statement, while retaining identical syntax.

Regardless of the spelling chosen, this introduces a stark difference between comprehensions and the equivalent unrolled long-hand form of the loop. It is no longer possible to unwrap the loop into statement form without reworking any name bindings. The only keyword that can be repurposed to this task is with , thus giving it sneakily different semantics in a comprehension than in a statement; alternatively, a new keyword is needed, with all the costs therein.

There are two logical precedences for the := operator. Either it should bind as loosely as possible, as does statement-assignment; or it should bind more tightly than comparison operators. Placing its precedence between the comparison and arithmetic operators (to be precise: just lower than bitwise OR) allows most uses inside while and if conditions to be spelled without parentheses, as it is most likely that you wish to capture the value of something, then perform a comparison on it:

Once find() returns -1, the loop terminates. If := binds as loosely as = does, this would capture the result of the comparison (generally either True or False ), which is less useful.

While this behaviour would be convenient in many situations, it is also harder to explain than “the := operator behaves just like the assignment statement”, and as such, the precedence for := has been made as close as possible to that of = (with the exception that it binds tighter than comma).

Some critics have claimed that the assignment expressions should allow unparenthesized tuples on the right, so that these two would be equivalent:

(With the current version of the proposal, the latter would be equivalent to ((point := x), y) .)

However, adopting this stance would logically lead to the conclusion that when used in a function call, assignment expressions also bind less tight than comma, so we’d have the following confusing equivalence:

The less confusing option is to make := bind more tightly than comma.

It’s been proposed to just always require parentheses around an assignment expression. This would resolve many ambiguities, and indeed parentheses will frequently be needed to extract the desired subexpression. But in the following cases the extra parentheses feel redundant:

Frequently Raised Objections

C and its derivatives define the = operator as an expression, rather than a statement as is Python’s way. This allows assignments in more contexts, including contexts where comparisons are more common. The syntactic similarity between if (x == y) and if (x = y) belies their drastically different semantics. Thus this proposal uses := to clarify the distinction.

The two forms have different flexibilities. The := operator can be used inside a larger expression; the = statement can be augmented to += and its friends, can be chained, and can assign to attributes and subscripts.

Previous revisions of this proposal involved sublocal scope (restricted to a single statement), preventing name leakage and namespace pollution. While a definite advantage in a number of situations, this increases complexity in many others, and the costs are not justified by the benefits. In the interests of language simplicity, the name bindings created here are exactly equivalent to any other name bindings, including that usage at class or module scope will create externally-visible names. This is no different from for loops or other constructs, and can be solved the same way: del the name once it is no longer needed, or prefix it with an underscore.

(The author wishes to thank Guido van Rossum and Christoph Groth for their suggestions to move the proposal in this direction. [2] )

As expression assignments can sometimes be used equivalently to statement assignments, the question of which should be preferred will arise. For the benefit of style guides such as PEP 8 , two recommendations are suggested.

  • If either assignment statements or assignment expressions can be used, prefer statements; they are a clear declaration of intent.
  • If using assignment expressions would lead to ambiguity about execution order, restructure it to use statements instead.

The authors wish to thank Alyssa Coghlan and Steven D’Aprano for their considerable contributions to this proposal, and members of the core-mentorship mailing list for assistance with implementation.

Appendix A: Tim Peters’s findings

Here’s a brief essay Tim Peters wrote on the topic.

I dislike “busy” lines of code, and also dislike putting conceptually unrelated logic on a single line. So, for example, instead of:

instead. So I suspected I’d find few places I’d want to use assignment expressions. I didn’t even consider them for lines already stretching halfway across the screen. In other cases, “unrelated” ruled:

is a vast improvement over the briefer:

The original two statements are doing entirely different conceptual things, and slamming them together is conceptually insane.

In other cases, combining related logic made it harder to understand, such as rewriting:

as the briefer:

The while test there is too subtle, crucially relying on strict left-to-right evaluation in a non-short-circuiting or method-chaining context. My brain isn’t wired that way.

But cases like that were rare. Name binding is very frequent, and “sparse is better than dense” does not mean “almost empty is better than sparse”. For example, I have many functions that return None or 0 to communicate “I have nothing useful to return in this case, but since that’s expected often I’m not going to annoy you with an exception”. This is essentially the same as regular expression search functions returning None when there is no match. So there was lots of code of the form:

I find that clearer, and certainly a bit less typing and pattern-matching reading, as:

It’s also nice to trade away a small amount of horizontal whitespace to get another _line_ of surrounding code on screen. I didn’t give much weight to this at first, but it was so very frequent it added up, and I soon enough became annoyed that I couldn’t actually run the briefer code. That surprised me!

There are other cases where assignment expressions really shine. Rather than pick another from my code, Kirill Balunov gave a lovely example from the standard library’s copy() function in copy.py :

The ever-increasing indentation is semantically misleading: the logic is conceptually flat, “the first test that succeeds wins”:

Using easy assignment expressions allows the visual structure of the code to emphasize the conceptual flatness of the logic; ever-increasing indentation obscured it.

A smaller example from my code delighted me, both allowing to put inherently related logic in a single line, and allowing to remove an annoying “artificial” indentation level:

That if is about as long as I want my lines to get, but remains easy to follow.

So, in all, in most lines binding a name, I wouldn’t use assignment expressions, but because that construct is so very frequent, that leaves many places I would. In most of the latter, I found a small win that adds up due to how often it occurs, and in the rest I found a moderate to major win. I’d certainly use it more often than ternary if , but significantly less often than augmented assignment.

I have another example that quite impressed me at the time.

Where all variables are positive integers, and a is at least as large as the n’th root of x, this algorithm returns the floor of the n’th root of x (and roughly doubling the number of accurate bits per iteration):

It’s not obvious why that works, but is no more obvious in the “loop and a half” form. It’s hard to prove correctness without building on the right insight (the “arithmetic mean - geometric mean inequality”), and knowing some non-trivial things about how nested floor functions behave. That is, the challenges are in the math, not really in the coding.

If you do know all that, then the assignment-expression form is easily read as “while the current guess is too large, get a smaller guess”, where the “too large?” test and the new guess share an expensive sub-expression.

To my eyes, the original form is harder to understand:

This appendix attempts to clarify (though not specify) the rules when a target occurs in a comprehension or in a generator expression. For a number of illustrative examples we show the original code, containing a comprehension, and the translation, where the comprehension has been replaced by an equivalent generator function plus some scaffolding.

Since [x for ...] is equivalent to list(x for ...) these examples all use list comprehensions without loss of generality. And since these examples are meant to clarify edge cases of the rules, they aren’t trying to look like real code.

Note: comprehensions are already implemented via synthesizing nested generator functions like those in this appendix. The new part is adding appropriate declarations to establish the intended scope of assignment expression targets (the same scope they resolve to as if the assignment were performed in the block containing the outermost comprehension). For type inference purposes, these illustrative expansions do not imply that assignment expression targets are always Optional (but they do indicate the target binding scope).

Let’s start with a reminder of what code is generated for a generator expression without assignment expression.

  • Original code (EXPR usually references VAR): def f (): a = [ EXPR for VAR in ITERABLE ]
  • Translation (let’s not worry about name conflicts): def f (): def genexpr ( iterator ): for VAR in iterator : yield EXPR a = list ( genexpr ( iter ( ITERABLE )))

Let’s add a simple assignment expression.

  • Original code: def f (): a = [ TARGET := EXPR for VAR in ITERABLE ]
  • Translation: def f (): if False : TARGET = None # Dead code to ensure TARGET is a local variable def genexpr ( iterator ): nonlocal TARGET for VAR in iterator : TARGET = EXPR yield TARGET a = list ( genexpr ( iter ( ITERABLE )))

Let’s add a global TARGET declaration in f() .

  • Original code: def f (): global TARGET a = [ TARGET := EXPR for VAR in ITERABLE ]
  • Translation: def f (): global TARGET def genexpr ( iterator ): global TARGET for VAR in iterator : TARGET = EXPR yield TARGET a = list ( genexpr ( iter ( ITERABLE )))

Or instead let’s add a nonlocal TARGET declaration in f() .

  • Original code: def g (): TARGET = ... def f (): nonlocal TARGET a = [ TARGET := EXPR for VAR in ITERABLE ]
  • Translation: def g (): TARGET = ... def f (): nonlocal TARGET def genexpr ( iterator ): nonlocal TARGET for VAR in iterator : TARGET = EXPR yield TARGET a = list ( genexpr ( iter ( ITERABLE )))

Finally, let’s nest two comprehensions.

  • Original code: def f (): a = [[ TARGET := i for i in range ( 3 )] for j in range ( 2 )] # I.e., a = [[0, 1, 2], [0, 1, 2]] print ( TARGET ) # prints 2
  • Translation: def f (): if False : TARGET = None def outer_genexpr ( outer_iterator ): nonlocal TARGET def inner_generator ( inner_iterator ): nonlocal TARGET for i in inner_iterator : TARGET = i yield i for j in outer_iterator : yield list ( inner_generator ( range ( 3 ))) a = list ( outer_genexpr ( range ( 2 ))) print ( TARGET )

Because it has been a point of confusion, note that nothing about Python’s scoping semantics is changed. Function-local scopes continue to be resolved at compile time, and to have indefinite temporal extent at run time (“full closures”). Example:

This document has been placed in the public domain.

Source: https://github.com/python/peps/blob/main/peps/pep-0572.rst

Last modified: 2023-10-11 12:05:51 GMT

Currently Reading :

Currently reading:

Simple assignment operator in Python

Different assignment operators in python.

Rajat Gupta

Software Developer

Published on  Thu Jun 30 2022

Assignment operators in Python are in-fix which are used to perform operations on variables or operands and assign values to the operand on the left side of the operator. It performs arithmetic, logical, and bitwise computations.

Assignment Operators in Python

Add and equal operator, subtract and equal operator, multiply and equal operator, divide and equal operator, modulus and equal operator, double divide and equal operator, exponent assign operator.

  • Bitwise and operator

Bitwise OR operator

  • Bitwise XOR Assignment operator

Bitwise right shift assignment operator

Bitwise left shift assignment operator.

The Simple assignment operator in Python is denoted by = and is used to assign values from the right side of the operator to the value on the left side.

This operator adds the value on the right side to the value on the left side and stores the result in the operand on the left side.

This operator subtracts the value on the right side from the value on the left side and stores the result in the operand on the left side.

The Multiply and equal operator multiplies the right operand with the left operand and then stores the result in the left operand.

It divides the left operand with the right operand and then stores the quotient in the left operand.

The modulus and equal operator finds the modulus from the left and right operand and stores the final result in the left operand.

The double divide and equal or the divide floor and equal operator divides the left operand with the right operand and stores the floor result in the left operand.

It performs exponential or power calculation and assigns value to the left operand.

Bitwise And operator

Performs Bitwise And operation on both variables and stores the result in the left operand. The Bitwise And operation compares the corresponding bits of the left operand to the bits of the right operand and if both bits are 1, the corresponding result is also 1 otherwise 0.

The binary value of 3 is 0011 and the binary value of 5 is 0101, so when the Bitwise And operation is performed on both the values, we get 0111, which is 7 in decimal.

Performs Bitwise OR operator on both variables and stores the result in the left operand. The Bitwise OR operation compares the corresponding bits of the left operand to the bits of the right operand and if any one of the bit is 1, the corresponding result is also 1 otherwise 0.

The binary value of 5 is 0101 and the binary value of 10 is 1010, so when the Bitwise OR operation is performed on both the values, we get 1111, which is 15 in decimal .

Bitwise XOR operator

Performs Bitwise XOR operator on both variables and stores the result in the left operand. The Bitwise XOR operation compares the corresponding bits of the left operand to the bits of the right operand and if only one of the bit is 1, the corresponding result is also 1 otherwise 0.

The binary value of 5 is 0101 and the binary value of 9 is 1001, so when the Bitwise XOR operation is performed on both the values, we get 1100, which is 12 in decimal.

This operator performs a Bitwise right shift on the operands and stores the result in the left operand.

The binary value of 15 is 1111, so when the Bitwise right shift operation is performed on ‘a’, we get 0011, which is 3 in decimal.

This operator performs a Bitwise left shift on the operands and stores the result in the left operand.

The binary value of 15 is 1111, so when the Bitwise right shift operation is performed on ‘a’, we get 00011110, which is 30 in decimal.

Closing Thoughts

In this tutorial, we read about different types of assignment operators in Python which are special symbols used to perform arithmetic, logical and bitwise operations on the operands and store the result in the left side operand. One can read about other Python concepts here .

About the author

Rajat Gupta is an experienced financial analyst known for his deep insights into market trends and investment strategies. He excels in providing robust financial solutions that drive growth and stability.

Related Blogs

4 Ways to implement Python Switch Case Statement

Sanchitee Ladole

Converting String to Float in Python

Ancil Eric D'Silva

Memoization Using Decorators In Python

Harsh Pandey

Harsh Pandey

Python Increment - Everything you need to know

Theano Python Beginner Guide for Getting Started

Taygun Dogan

Taygun Dogan

17 min read

Python Classes And Objects

Browse Flexiple's talent pool

Explore our network of top tech talent. Find the perfect match for your dream team.

  • Programmers
  • React Native
  • Ruby on Rails

PrepBytes Blog

ONE-STOP RESOURCE FOR EVERYTHING RELATED TO CODING

Sign in to your account

Forgot your password?

Login via OTP

We will send you an one time password on your mobile number

An OTP has been sent to your mobile number please verify it below

Register with PrepBytes

Assignment operator in python.

' src=

Last Updated on June 8, 2023 by Prepbytes

and assignment operator in python

To fully comprehend the assignment operators in Python, it is important to have a basic understanding of what operators are. Operators are utilized to carry out a variety of operations, including mathematical, bitwise, and logical operations, among others, by connecting operands. Operands are the values that are acted upon by operators. In Python, the assignment operator is used to assign a value to a variable. The assignment operator is represented by the equals sign (=), and it is the most commonly used operator in Python. In this article, we will explore the assignment operator in Python, how it works, and its different types.

What is an Assignment Operator in Python?

The assignment operator in Python is used to assign a value to a variable. The assignment operator is represented by the equals sign (=), and it is used to assign a value to a variable. When an assignment operator is used, the value on the right-hand side is assigned to the variable on the left-hand side. This is a fundamental operation in programming, as it allows developers to store data in variables that can be used throughout their code.

For example, consider the following line of code:

Explanation: In this case, the value 10 is assigned to the variable a using the assignment operator. The variable a now holds the value 10, and this value can be used in other parts of the code. This simple example illustrates the basic usage and importance of assignment operators in Python programming.

Types of Assignment Operator in Python

There are several types of assignment operator in Python that are used to perform different operations. Let’s explore each type of assignment operator in Python in detail with the help of some code examples.

1. Simple Assignment Operator (=)

The simple assignment operator is the most commonly used operator in Python. It is used to assign a value to a variable. The syntax for the simple assignment operator is:

Here, the value on the right-hand side of the equals sign is assigned to the variable on the left-hand side. For example

Explanation: In this case, the value 25 is assigned to the variable a using the simple assignment operator. The variable a now holds the value 25.

2. Addition Assignment Operator (+=)

The addition assignment operator is used to add a value to a variable and store the result in the same variable. The syntax for the addition assignment operator is:

Here, the value on the right-hand side is added to the variable on the left-hand side, and the result is stored back in the variable on the left-hand side. For example

Explanation: In this case, the value of a is incremented by 5 using the addition assignment operator. The result, 15, is then printed to the console.

3. Subtraction Assignment Operator (-=)

The subtraction assignment operator is used to subtract a value from a variable and store the result in the same variable. The syntax for the subtraction assignment operator is

Here, the value on the right-hand side is subtracted from the variable on the left-hand side, and the result is stored back in the variable on the left-hand side. For example

Explanation: In this case, the value of a is decremented by 5 using the subtraction assignment operator. The result, 5, is then printed to the console.

4. Multiplication Assignment Operator (*=)

The multiplication assignment operator is used to multiply a variable by a value and store the result in the same variable. The syntax for the multiplication assignment operator is:

Here, the value on the right-hand side is multiplied by the variable on the left-hand side, and the result is stored back in the variable on the left-hand side. For example

Explanation: In this case, the value of a is multiplied by 5 using the multiplication assignment operator. The result, 50, is then printed to the console.

5. Division Assignment Operator (/=)

The division assignment operator is used to divide a variable by a value and store the result in the same variable. The syntax for the division assignment operator is:

Here, the variable on the left-hand side is divided by the value on the right-hand side, and the result is stored back in the variable on the left-hand side. For example

Explanation: In this case, the value of a is divided by 5 using the division assignment operator. The result, 2.0, is then printed to the console.

6. Modulus Assignment Operator (%=)

The modulus assignment operator is used to find the remainder of the division of a variable by a value and store the result in the same variable. The syntax for the modulus assignment operator is

Here, the variable on the left-hand side is divided by the value on the right-hand side, and the remainder is stored back in the variable on the left-hand side. For example

Explanation: In this case, the value of a is divided by 3 using the modulus assignment operator. The remainder, 1, is then printed to the console.

7. Floor Division Assignment Operator (//=)

The floor division assignment operator is used to divide a variable by a value and round the result down to the nearest integer, and store the result in the same variable. The syntax for the floor division assignment operator is:

Here, the variable on the left-hand side is divided by the value on the right-hand side, and the result is rounded down to the nearest integer. The rounded result is then stored back in the variable on the left-hand side. For example

Explanation: In this case, the value of a is divided by 3 using the floor division assignment operator. The result, 3, is then printed to the console.

8. Exponentiation Assignment Operator (**=)

The exponentiation assignment operator is used to raise a variable to the power of a value and store the result in the same variable. The syntax for the exponentiation assignment operator is:

Here, the variable on the left-hand side is raised to the power of the value on the right-hand side, and the result is stored back in the variable on the left-hand side. For example

Explanation: In this case, the value of a is raised to the power of 3 using the exponentiation assignment operator. The result, 8, is then printed to the console.

9. Bitwise AND Assignment Operator (&=)

The bitwise AND assignment operator is used to perform a bitwise AND operation on the binary representation of a variable and a value, and store the result in the same variable. The syntax for the bitwise AND assignment operator is:

Here, the variable on the left-hand side is ANDed with the value on the right-hand side using the bitwise AND operator, and the result is stored back in the variable on the left-hand side. For example,

Explanation: In this case, the value of a is ANDed with 3 using the bitwise AND assignment operator. The result, 2, is then printed to the console.

10. Bitwise OR Assignment Operator (|=)

The bitwise OR assignment operator is used to perform a bitwise OR operation on the binary representation of a variable and a value, and store the result in the same variable. The syntax for the bitwise OR assignment operator is:

Here, the variable on the left-hand side is ORed with the value on the right-hand side using the bitwise OR operator, and the result is stored back in the variable on the left-hand side. For example,

Explanation: In this case, the value of a is ORed with 3 using the bitwise OR assignment operator. The result, 7, is then printed to the console.

11. Bitwise XOR Assignment Operator (^=)

The bitwise XOR assignment operator is used to perform a bitwise XOR operation on the binary representation of a variable and a value, and store the result in the same variable. The syntax for the bitwise XOR assignment operator is:

Here, the variable on the left-hand side is XORed with the value on the right-hand side using the bitwise XOR operator, and the result are stored back in the variable on the left-hand side. For example,

Explanation: In this case, the value of a is XORed with 3 using the bitwise XOR assignment operator. The result, 5, is then printed to the console.

12. Bitwise Right Shift Assignment Operator (>>=)

The bitwise right shift assignment operator is used to shift the bits of a variable to the right by a specified number of positions, and store the result in the same variable. The syntax for the bitwise right shift assignment operator is:

Here, the variable on the left-hand side has its bits shifted to the right by the number of positions specified by the value on the right-hand side, and the result is stored back in the variable on the left-hand side. For example,

Explanation: In this case, the value of a is shifted 2 positions to the right using the bitwise right shift assignment operator. The result, 2, is then printed to the console.

13. Bitwise Left Shift Assignment Operator (<<=)

The bitwise left shift assignment operator is used to shift the bits of a variable to the left by a specified number of positions, and store the result in the same variable. The syntax for the bitwise left shift assignment operator is:

Here, the variable on the left-hand side has its bits shifted to the left by the number of positions specified by the value on the right-hand side, and the result is stored back in the variable on the left-hand side. For example,

Conclusion Assignment operator in Python is used to assign values to variables, and it comes in different types. The simple assignment operator (=) assigns a value to a variable. The augmented assignment operators (+=, -=, *=, /=, %=, &=, |=, ^=, >>=, <<=) perform a specified operation and assign the result to the same variable in one step. The modulus assignment operator (%) calculates the remainder of a division operation and assigns the result to the same variable. The bitwise assignment operators (&=, |=, ^=, >>=, <<=) perform bitwise operations and assign the result to the same variable. The bitwise right shift assignment operator (>>=) shifts the bits of a variable to the right by a specified number of positions and stores the result in the same variable. The bitwise left shift assignment operator (<<=) shifts the bits of a variable to the left by a specified number of positions and stores the result in the same variable. These operators are useful in simplifying and shortening code that involves assigning and manipulating values in a single step.

Here are some Frequently Asked Questions on Assignment Operator in Python:

Q1 – Can I use the assignment operator to assign multiple values to multiple variables at once? Ans – Yes, you can use the assignment operator to assign multiple values to multiple variables at once, separated by commas. For example, "x, y, z = 1, 2, 3" would assign the value 1 to x, 2 to y, and 3 to z.

Q2 – Is it possible to chain assignment operators in Python? Ans – Yes, you can chain assignment operators in Python to perform multiple operations in one line of code. For example, "x = y = z = 1" would assign the value 1 to all three variables.

Q3 – How do I perform a conditional assignment in Python? Ans – To perform a conditional assignment in Python, you can use the ternary operator. For example, "x = a (if a > b) else b" would assign the value of a to x if a is greater than b, otherwise it would assign the value of b to x.

Q4 – What happens if I use an undefined variable in an assignment operation in Python? Ans – If you use an undefined variable in an assignment operation in Python, you will get a NameError. Make sure you have defined the variable before trying to assign a value to it.

Q5 – Can I use assignment operators with non-numeric data types in Python? Ans – Yes, you can use assignment operators with non-numeric data types in Python, such as strings or lists. For example, "my_list += [4, 5, 6]" would append the values 4, 5, and 6 to the end of the list named my_list.

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

Save my name, email, and website in this browser for the next time I comment.

  • Linked List
  • Segment Tree
  • Backtracking
  • Dynamic Programming
  • Greedy Algorithm
  • Operating System
  • Company Placement
  • Interview Tips
  • General Interview Questions
  • Data Structure
  • Other Topics
  • Computational Geometry
  • Game Theory

Related Post

Python list functions & python list methods, python interview questions, namespaces and scope in python, what is the difference between append and extend in python, python program to check for the perfect square, python program to find the sum of first n natural numbers.

Learn Python practically and Get Certified .

Popular Tutorials

Popular examples, reference materials, learn python interactively, python introduction.

  • Get Started With Python
  • Your First Python Program
  • Python Comments

Python Fundamentals

  • Python Variables and Literals
  • Python Type Conversion
  • Python Basic Input and Output

Python Operators

Python flow control.

Python if...else Statement

  • Python for Loop
  • Python while Loop
  • Python break and continue
  • Python pass Statement

Python Data types

  • Python Numbers and Mathematics
  • Python List
  • Python Tuple
  • Python String
  • Python Sets
  • Python Dictionary
  • Python Functions
  • Python Function Arguments
  • Python Variable Scope
  • Python Global Keyword
  • Python Recursion
  • Python Modules
  • Python Package
  • Python Main function

Python Files

  • Python Directory and Files Management
  • Python CSV: Read and Write CSV files
  • Reading CSV files in Python
  • Writing CSV files in Python
  • Python Exception Handling
  • Python Exceptions
  • Python Custom Exceptions

Python Object & Class

  • Python Objects and Classes
  • Python Inheritance
  • Python Multiple Inheritance
  • Polymorphism in Python

Python Operator Overloading

Python Advanced Topics

  • List comprehension
  • Python Lambda/Anonymous Function
  • Python Iterators
  • Python Generators
  • Python Namespace and Scope
  • Python Closures
  • Python Decorators
  • Python @property decorator
  • Python RegEx

Python Date and Time

  • Python datetime
  • Python strftime()
  • Python strptime()
  • How to get current date and time in Python?
  • Python Get Current Time
  • Python timestamp to datetime and vice-versa
  • Python time Module
  • Python sleep()

Additional Topic

Precedence and Associativity of Operators in Python

  • Python Keywords and Identifiers
  • Python Asserts
  • Python Json
  • Python *args and **kwargs

Python Tutorials

Python 3 Tutorial

  • Python Strings
  • Python any()

Operators are special symbols that perform operations on variables and values. For example,

Here, + is an operator that adds two numbers: 5 and 6 .

  • Types of Python Operators

Here's a list of different types of Python operators that we will learn in this tutorial.

  • Arithmetic Operators
  • Assignment Operators
  • Comparison Operators
  • Logical Operators
  • Bitwise Operators
  • Special Operators

1. Python Arithmetic Operators

Arithmetic operators are used to perform mathematical operations like addition, subtraction, multiplication, etc. For example,

Here, - is an arithmetic operator that subtracts two values or variables.

Example 1: Arithmetic Operators in Python

In the above example, we have used multiple arithmetic operators,

  • + to add a and b
  • - to subtract b from a
  • * to multiply a and b
  • / to divide a by b
  • // to floor divide a by b
  • % to get the remainder
  • ** to get a to the power b

2. Python Assignment Operators

Assignment operators are used to assign values to variables. For example,

Here, = is an assignment operator that assigns 5 to x .

Here's a list of different assignment operators available in Python.

Example 2: Assignment Operators

Here, we have used the += operator to assign the sum of a and b to a .

Similarly, we can use any other assignment operators as per our needs.

3. Python Comparison Operators

Comparison operators compare two values/variables and return a boolean result: True or False . For example,

Here, the > comparison operator is used to compare whether a is greater than b or not.

Example 3: Comparison Operators

Note: Comparison operators are used in decision-making and loops . We'll discuss more of the comparison operator and decision-making in later tutorials.

4. Python Logical Operators

Logical operators are used to check whether an expression is True or False . They are used in decision-making. For example,

Here, and is the logical operator AND . Since both a > 2 and b >= 6 are True , the result is True .

Example 4: Logical Operators

Note : Here is the truth table for these logical operators.

5. Python Bitwise operators

Bitwise operators act on operands as if they were strings of binary digits. They operate bit by bit, hence the name.

For example, 2 is 10 in binary, and 7 is 111 .

In the table below: Let x = 10 ( 0000 1010 in binary) and y = 4 ( 0000 0100 in binary)

6. Python Special operators

Python language offers some special types of operators like the identity operator and the membership operator. They are described below with examples.

  • Identity operators

In Python, is and is not are used to check if two values are located at the same memory location.

It's important to note that having two variables with equal values doesn't necessarily mean they are identical.

Example 4: Identity operators in Python

Here, we see that x1 and y1 are integers of the same values, so they are equal as well as identical. The same is the case with x2 and y2 (strings).

But x3 and y3 are lists. They are equal but not identical. It is because the interpreter locates them separately in memory, although they are equal.

  • Membership operators

In Python, in and not in are the membership operators. They are used to test whether a value or variable is found in a sequence ( string , list , tuple , set and dictionary ).

In a dictionary, we can only test for the presence of a key, not the value.

Example 5: Membership operators in Python

Here, 'H' is in message , but 'hello' is not present in message (remember, Python is case-sensitive).

Similarly, 1 is key, and 'a' is the value in dictionary dict1 . Hence, 'a' in y returns False .

  • Precedence and Associativity of operators in Python

Table of Contents

  • Introduction
  • Python Arithmetic Operators
  • Python Assignment Operators
  • Python Comparison Operators
  • Python Logical Operators
  • Python Bitwise operators
  • Python Special operators

Video: Operators in Python

Sorry about that.

Related Tutorials

Python Tutorial

Python Tutorial

  • Python Basics
  • Python - Home
  • Python - Overview
  • Python - History
  • Python - Features
  • Python vs C++
  • Python - Hello World Program
  • Python - Application Areas
  • Python - Interpreter
  • Python - Environment Setup
  • Python - Virtual Environment
  • Python - Basic Syntax
  • Python - Variables
  • Python - Data Types
  • Python - Type Casting
  • Python - Unicode System
  • Python - Literals
  • Python - Operators
  • Python - Arithmetic Operators
  • Python - Comparison Operators

Python - Assignment Operators

  • Python - Logical Operators
  • Python - Bitwise Operators
  • Python - Membership Operators
  • Python - Identity Operators
  • Python - Operator Precedence
  • Python - Comments
  • Python - User Input
  • Python - Numbers
  • Python - Booleans
  • Python Control Statements
  • Python - Control Flow
  • Python - Decision Making
  • Python - If Statement
  • Python - If else
  • Python - Nested If
  • Python - Match-Case Statement
  • Python - Loops
  • Python - for Loops
  • Python - for-else Loops
  • Python - While Loops
  • Python - break Statement
  • Python - continue Statement
  • Python - pass Statement
  • Python - Nested Loops
  • Python Functions & Modules
  • Python - Functions
  • Python - Default Arguments
  • Python - Keyword Arguments
  • Python - Keyword-Only Arguments
  • Python - Positional Arguments
  • Python - Positional-Only Arguments
  • Python - Arbitrary Arguments
  • Python - Variables Scope
  • Python - Function Annotations
  • Python - Modules
  • Python - Built in Functions
  • Python Strings
  • Python - Strings
  • Python - Slicing Strings
  • Python - Modify Strings
  • Python - String Concatenation
  • Python - String Formatting
  • Python - Escape Characters
  • Python - String Methods
  • Python - String Exercises
  • Python Lists
  • Python - Lists
  • Python - Access List Items
  • Python - Change List Items
  • Python - Add List Items
  • Python - Remove List Items
  • Python - Loop Lists
  • Python - List Comprehension
  • Python - Sort Lists
  • Python - Copy Lists
  • Python - Join Lists
  • Python - List Methods
  • Python - List Exercises
  • Python Tuples
  • Python - Tuples
  • Python - Access Tuple Items
  • Python - Update Tuples
  • Python - Unpack Tuples
  • Python - Loop Tuples
  • Python - Join Tuples
  • Python - Tuple Methods
  • Python - Tuple Exercises
  • Python Sets
  • Python - Sets
  • Python - Access Set Items
  • Python - Add Set Items
  • Python - Remove Set Items
  • Python - Loop Sets
  • Python - Join Sets
  • Python - Copy Sets
  • Python - Set Operators
  • Python - Set Methods
  • Python - Set Exercises
  • Python Dictionaries
  • Python - Dictionaries
  • Python - Access Dictionary Items
  • Python - Change Dictionary Items
  • Python - Add Dictionary Items
  • Python - Remove Dictionary Items
  • Python - Dictionary View Objects
  • Python - Loop Dictionaries
  • Python - Copy Dictionaries
  • Python - Nested Dictionaries
  • Python - Dictionary Methods
  • Python - Dictionary Exercises
  • Python Arrays
  • Python - Arrays
  • Python - Access Array Items
  • Python - Add Array Items
  • Python - Remove Array Items
  • Python - Loop Arrays
  • Python - Copy Arrays
  • Python - Reverse Arrays
  • Python - Sort Arrays
  • Python - Join Arrays
  • Python - Array Methods
  • Python - Array Exercises
  • Python File Handling
  • Python - File Handling
  • Python - Write to File
  • Python - Read Files
  • Python - Renaming and Deleting Files
  • Python - Directories
  • Python - File Methods
  • Python - OS File/Directory Methods
  • Object Oriented Programming
  • Python - OOPs Concepts
  • Python - Object & Classes
  • Python - Class Attributes
  • Python - Class Methods
  • Python - Static Methods
  • Python - Constructors
  • Python - Access Modifiers
  • Python - Inheritance
  • Python - Polymorphism
  • Python - Method Overriding
  • Python - Method Overloading
  • Python - Dynamic Binding
  • Python - Dynamic Typing
  • Python - Abstraction
  • Python - Encapsulation
  • Python - Interfaces
  • Python - Packages
  • Python - Inner Classes
  • Python - Anonymous Class and Objects
  • Python - Singleton Class
  • Python - Wrapper Classes
  • Python - Enums
  • Python - Reflection
  • Python Errors & Exceptions
  • Python - Syntax Errors
  • Python - Exceptions
  • Python - try-except Block
  • Python - try-finally Block
  • Python - Raising Exceptions
  • Python - Exception Chaining
  • Python - Nested try Block
  • Python - User-defined Exception
  • Python - Logging
  • Python - Assertions
  • Python - Built-in Exceptions
  • Python Multithreading
  • Python - Multithreading
  • Python - Thread Life Cycle
  • Python - Creating a Thread
  • Python - Starting a Thread
  • Python - Joining Threads
  • Python - Naming Thread
  • Python - Thread Scheduling
  • Python - Thread Pools
  • Python - Main Thread
  • Python - Thread Priority
  • Python - Daemon Threads
  • Python - Synchronizing Threads
  • Python Synchronization
  • Python - Inter-thread Communication
  • Python - Thread Deadlock
  • Python - Interrupting a Thread
  • Python Networking
  • Python - Networking
  • Python - Socket Programming
  • Python - URL Processing
  • Python - Generics
  • Python Libraries
  • NumPy Tutorial
  • Pandas Tutorial
  • SciPy Tutorial
  • Matplotlib Tutorial
  • Django Tutorial
  • OpenCV Tutorial
  • Python Miscellenous
  • Python - Date & Time
  • Python - Maths
  • Python - Iterators
  • Python - Generators
  • Python - Closures
  • Python - Decorators
  • Python - Recursion
  • Python - Reg Expressions
  • Python - PIP
  • Python - Database Access
  • Python - Weak References
  • Python - Serialization
  • Python - Templating
  • Python - Output Formatting
  • Python - Performance Measurement
  • Python - Data Compression
  • Python - CGI Programming
  • Python - XML Processing
  • Python - GUI Programming
  • Python - Command-Line Arguments
  • Python - Docstrings
  • Python - JSON
  • Python - Sending Email
  • Python - Further Extensions
  • Python - Tools/Utilities
  • Python - GUIs
  • Python Questions and Answers
  • Python Useful Resources
  • Python Compiler
  • NumPy Compiler
  • Matplotlib Compiler
  • SciPy Compiler
  • Python - Programming Examples
  • Python - Quick Guide
  • Python - Useful Resources
  • Python - Discussion
  • Selected Reading
  • UPSC IAS Exams Notes
  • Developer's Best Practices
  • Questions and Answers
  • Effective Resume Writing
  • HR Interview Questions
  • Computer Glossary

Python Assignment Operator

The = (equal to) symbol is defined as assignment operator in Python. The value of Python expression on its right is assigned to a single variable on its left. The = symbol as in programming in general (and Python in particular) should not be confused with its usage in Mathematics, where it states that the expressions on the either side of the symbol are equal.

Example of Assignment Operator in Python

Consider following Python statements −

At the first instance, at least for somebody new to programming but who knows maths, the statement "a=a+b" looks strange. How could a be equal to "a+b"? However, it needs to be reemphasized that the = symbol is an assignment operator here and not used to show the equality of LHS and RHS.

Because it is an assignment, the expression on right evaluates to 15, the value is assigned to a.

In the statement "a+=b", the two operators "+" and "=" can be combined in a "+=" operator. It is called as add and assign operator. In a single statement, it performs addition of two operands "a" and "b", and result is assigned to operand on left, i.e., "a".

Augmented Assignment Operators in Python

In addition to the simple assignment operator, Python provides few more assignment operators for advanced use. They are called cumulative or augmented assignment operators. In this chapter, we shall learn to use augmented assignment operators defined in Python.

Python has the augmented assignment operators for all arithmetic and comparison operators.

Python augmented assignment operators combines addition and assignment in one statement. Since Python supports mixed arithmetic, the two operands may be of different types. However, the type of left operand changes to the operand of on right, if it is wider.

The += operator is an augmented operator. It is also called cumulative addition operator, as it adds "b" in "a" and assigns the result back to a variable.

The following are the augmented assignment operators in Python:

  • Augmented Addition Operator
  • Augmented Subtraction Operator
  • Augmented Multiplication Operator
  • Augmented Division Operator
  • Augmented Modulus Operator
  • Augmented Exponent Operator
  • Augmented Floor division Operator

Augmented Addition Operator (+=)

Following examples will help in understanding how the "+=" operator works −

It will produce the following output −

Augmented Subtraction Operator (-=)

Use -= symbol to perform subtract and assign operations in a single statement. The "a-=b" statement performs "a=a-b" assignment. Operands may be of any number type. Python performs implicit type casting on the object which is narrower in size.

Augmented Multiplication Operator (*=)

The "*=" operator works on similar principle. "a*=b" performs multiply and assign operations, and is equivalent to "a=a*b". In case of augmented multiplication of two complex numbers, the rule of multiplication as discussed in the previous chapter is applicable.

Augmented Division Operator (/=)

The combination symbol "/=" acts as divide and assignment operator, hence "a/=b" is equivalent to "a=a/b". The division operation of int or float operands is float. Division of two complex numbers returns a complex number. Given below are examples of augmented division operator.

Augmented Modulus Operator (%=)

To perform modulus and assignment operation in a single statement, use the %= operator. Like the mod operator, its augmented version also is not supported for complex number.

Augmented Exponent Operator (**=)

The "**=" operator results in computation of "a" raised to "b", and assigning the value back to "a". Given below are some examples −

Augmented Floor division Operator (//=)

For performing floor division and assignment in a single statement, use the "//=" operator. "a//=b" is equivalent to "a=a//b". This operator cannot be used with complex numbers.

To Continue Learning Please Login

Python Tutorial

File handling, python modules, python numpy, python pandas, python matplotlib, python scipy, machine learning, python mysql, python mongodb, python reference, module reference, python how to, python examples, python operators.

Operators are used to perform operations on variables and values.

In the example below, we use the + operator to add together two values:

Python divides the operators in the following groups:

  • Arithmetic operators
  • Assignment operators
  • Comparison operators
  • Logical operators
  • Identity operators
  • Membership operators
  • Bitwise operators

Python Arithmetic Operators

Arithmetic operators are used with numeric values to perform common mathematical operations:

Python Assignment Operators

Assignment operators are used to assign values to variables:

Advertisement

Python Comparison Operators

Comparison operators are used to compare two values:

Python Logical Operators

Logical operators are used to combine conditional statements:

Python Identity Operators

Identity operators are used to compare the objects, not if they are equal, but if they are actually the same object, with the same memory location:

Python Membership Operators

Membership operators are used to test if a sequence is presented in an object:

Python Bitwise Operators

Bitwise operators are used to compare (binary) numbers:

Operator Precedence

Operator precedence describes the order in which operations are performed.

Parentheses has the highest precedence, meaning that expressions inside parentheses must be evaluated first:

Multiplication * has higher precedence than addition + , and therefor multiplications are evaluated before additions:

The precedence order is described in the table below, starting with the highest precedence at the top:

If two operators have the same precedence, the expression is evaluated from left to right.

Addition + and subtraction - has the same precedence, and therefor we evaluate the expression from left to right:

Test Yourself With Exercises

Multiply 10 with 5 , and print the result.

Start the Exercise

Get Certified

COLOR PICKER

colorpicker

Contact Sales

If you want to use W3Schools services as an educational institution, team or enterprise, send us an e-mail: [email protected]

Report Error

If you want to report an error, or if you want to make a suggestion, send us an e-mail: [email protected]

Top Tutorials

Top references, top examples, get certified.

Notice: While JavaScript is not essential for this website, your interaction with the content will be limited. Please turn JavaScript on for the full experience.

Notice: Your browser is ancient . Please upgrade to a different browser to experience a better web.

  • Chat on IRC
  • >_ Launch Interactive Shell

Functions Defined

The core of extensible programming is defining functions. Python allows mandatory and optional arguments, keyword arguments, and even arbitrary argument lists. More about defining functions in Python 3

Compound Data Types

Lists (known as arrays in other languages) are one of the compound data types that Python understands. Lists can be indexed, sliced and manipulated with other built-in functions. More about lists in Python 3

Intuitive Interpretation

Calculations are simple with Python, and expression syntax is straightforward: the operators + , - , * and / work as expected; parentheses () can be used for grouping. More about simple math functions in Python 3 .

All the Flow You’d Expect

Python knows the usual control flow statements that other languages speak — if , for , while and range — with some of its own twists, of course. More control flow tools in Python 3

Quick & Easy to Learn

Experienced programmers in any other language can pick up Python very quickly, and beginners find the clean syntax and indentation structure easy to learn. Whet your appetite with our Python 3 overview.

Python is a programming language that lets you work quickly and integrate systems more effectively. Learn More

Get Started

Whether you're new to programming or an experienced developer, it's easy to learn and use Python.

Start with our Beginner’s Guide

Python source code and installers are available for download for all versions!

Latest: Python 3.12.3

Documentation for Python's standard library, along with tutorials and guides, are available online.

docs.python.org

Looking for work or have a Python related position that you're trying to hire for? Our relaunched community-run job board is the place to go.

jobs.python.org

Latest News

  • 2024- 05-08 Python 3.13.0 beta 1 released
  • 2024- 05-08 PSF Grants Program 2022 & 2023 Transparency Report
  • 2024- 05-07 PSF Board Election Dates for 2024
  • 2024- 05-03 The PSF's 2023 Annual Impact Report is here!

Upcoming Events

  • 2024- 05-29 csv,conf,v8
  • 2024- 05-29 PyLadies Amsterdam: NLP projects with spaCy
  • 2024- 06-01 Django Girls Medellín
  • 2024- 06-01 Building Python Communities Yaounde
  • 2024- 06-05 DjangoCon Europe 2024

Success Stories

Thanks to the flexibility of Python and the powerful ecosystem of packages, the Azure CLI supports features such as autocompletion (in shells that support it), persistent credentials, JMESPath result parsing, lazy initialization, network-less unit tests, and more.

Use Python for…

  • Web Development : Django , Pyramid , Bottle , Tornado , Flask , web2py
  • GUI Development : tkInter , PyGObject , PyQt , PySide , Kivy , wxPython , DearPyGui
  • Scientific and Numeric : SciPy , Pandas , IPython
  • Software Development : Buildbot , Trac , Roundup
  • System Administration : Ansible , Salt , OpenStack , xonsh

>>> Python Enhancement Proposals (PEPs) : The future of Python is discussed here. RSS

>>> python software foundation.

The mission of the Python Software Foundation is to promote, protect, and advance the Python programming language, and to support and facilitate the growth of a diverse and international community of Python programmers. Learn more

Become a Member Donate to the PSF

Freethreading += operators (and similar)

Just considering the builtin numeric types here (so int , float , complex ).

In the freethreading build, suppose I have two threads both doing in-place mathematical operations. What is guaranteed? Are the operations “atomic” or is a += 1 split into:

  • replace a with the result. with the possibility that another thread could also write to a in the space between 2 and 3.

(I’m assuming that the one thing that is guaranteed is that the reference counting is fine, whatever else happens).

Are you just curious or are you having a specific problem you are addressing? Your answer may help us help you.

I’m asking from the point of view of implementing it in Cython (which currently isn’t very thread-safe, will have to get more thread-safe to support the free-threading build well, but I want to understand how thread-safe it ideally needs to be)

So I’m interested in “what does the interpreter guarantee?” rather than “should I write code with a bunch in place arithmetic operators, many threads, and no synchronisation?”. I know the answer to the second question is “no” but I also know people will do it anyway.

If using free threading, I believe you would have to use threading.Lock or something similar to guarantee deterministic behavior.

I don’t think things like += are guaranteed to be atomic.

Though it makes me think a stdlib of atomic numerics might be useful for some.

Related Topics

and assignment operator in python

Geospatial Think

and assignment operator in python

Conditional Statements in Python

Using if-statements to direct the execution of code.

and assignment operator in python

In Python, I can leverage logical comparisons to control the execution of my code. By using if-elif-else statements, I am introduced to a new data type: the Boolean value. Boolean values return either true or false to guide the flow of my program.

white and black One Way-printed road signages

How to Write If Statements

Statements are declared with a colon ( : ) at the end of the line. What follows is an indented code block to be executed when the statement returns a true value.

First comes an if statement, followed by optional elif statements, ending with an else statement.

Here’s an example of an if-elif-else chain comparing the value of two numbers:

Comparison Operators

Comparison Operators are fundamental for my program to make decisions. These operators allow me to create logical expressions that guide the flow of my code based on the relationships between values.

The comparison operators include:

Greater than >

Greater than or equal to >=

Less than <

Less than or equal to <=

Equal to ==

Not equal to !=

Comparison Operators can be combined with Boolean Operators to determine comparative conditions in if -statements. Boolean Operators include and, not, and or .

For example:

If-Statements

Remember, if -statements are meant to help direct the flow of a program. Let’s say I make a simple program to help determine what grade a student should receive based on a test score. In my first draft of code, I use multiple if- statements, but it doesn’t return the desired results. The output returned every possible grade assignment that would be true .

It isn’t helpful to run through every comparison when I need to assign only a single grade, but assessing each line of code might be helpful when taking a pizza order. I’d want every choice of topping considered in the final order.

Elif-Statements

The power of elif -statements is they allow for mutually exclusive lines of code. Only the first line of code that returns a true value is executed.

To improve my grading program from earlier, I’ll replace subsequent if -statements with elif- statements and finish with an else statement. Now students get only one grade.

Test the Code

When dealing with logical comparisons, I must thoroughly test my code to ensure that the logic produces accurate results. I can even create a flowchart before implementing the program. First, I design the script and then verify its functionality. Once I’m confident it works correctly, a skilled programmer will ask, “How can I improve and streamline this code?”

Thanks for reading Geospatial Think ! Subscribe to receive new posts and support my work.

and assignment operator in python

About the Author

Stephanie Scavelli is a tech writer passionate about sharing the joy of geospatial thinking in this ever-advancing technological world. She is based out of the Lower Hudson Valley in New York State (USA).

and assignment operator in python

Ready for more?

  • C++ Data Types
  • C++ Input/Output
  • C++ Pointers
  • C++ Interview Questions
  • C++ Programs
  • C++ Cheatsheet
  • C++ Projects
  • C++ Exception Handling
  • C++ Memory Management
  • Operator Precedence and Associativity in C
  • Difference between Operator Precedence and Operator Associativity
  • Operator Associativity in Programming
  • Operator precedence in JavaScript
  • Floating Point Operations & Associativity in C, C++ and Java
  • Precedence of postfix ++ and prefix ++ in C/C++
  • Bitwise AND operator in Programming
  • Assignment Operators In C++
  • Assignment Operators in C
  • Result of comma operator as l-value in C and C++
  • Self assignment check in assignment operator
  • Assignment Operators in Programming
  • bitset operator[] in C++ STL
  • Precedence and Associativity of Operators in Python
  • Operator grammar and precedence parser in TOC
  • Operator Precedence in Ruby
  • MySQL | Operator precedence
  • Operators Precedence in Scala
  • Precedence Graph in Operating System

Operator Precedence and Associativity in C++

In C++, operator precedence and associativity are important concepts that determine the order in which operators are evaluated in an expression. Operator precedence tells the priority of operators, while associativity determines the order of evaluation when multiple operators of the same precedence level are present.

Operator Precedence in C++

In C++, operator precedence specifies the order in which operations are performed within an expression. When an expression contains multiple operators, those with higher precedence are evaluated before those with lower precedence.

For expression:

As, multiplication has higher precedence than subtraction, that’s why 17 * 6 is evaluated first, resulting in x = -97 . If we want to evaluate 5 – 17 first, we can use parentheses:

Now 5 – 17 is evaluated first, resulting in x = -72 .

Example of C++ Operator Precedence

Remember that, using parentheses makes code more readable, especially when dealing with complex expressions.

Operator Associativity in C++

Operator associativity determines the order in which operands are grouped when multiple operators have the same precedence. There are two types of associativity:

Left-to-right associativity: In expressions like a + b – c, the addition and subtraction operators are evaluated from left to right. So, (a + b) – c is equivalent.

Right-to-left associativity: Some operators, like the assignment operator =, have right-to-left associativity. For example, a = b = 4; assigns the value of b to a.

As, subtraction is left-associative, that’s why 10 – 5 evaluated first, resulting in x = 3 . But in case of multiplication:

Now 3 * 4 is evaluated first, resulting in x = 24 because multiplication is right-associative.

Example of C++ Operator Associativity

Understanding both the precedence and associativity of operators is crucial for writing expressions that produce the desired results.

Operator Precedence Table in C++

The operator precedence table in C++ is a table that lists the operators in order of their precedence level. Operators with higher precedence are evaluated before operators with lower precedence. This table also includes the associativity of the operators, which determines the order in which operators of the same precedence are processed.

The operators are listed from top to bottom, in descending precedence

Please Login to comment...

Similar reads.

author

  • cpp-operator

Improve your Coding Skills with Practice

 alt=

What kind of Experience do you want to share?

and assignment operator in python

Article  

  • Volume 17, issue 10
  • GMD, 17, 4355–4382, 2024
  • Peer review
  • Related articles

and assignment operator in python

VISIR-2: ship weather routing in Python

Gianandrea mannarini, mario leonardo salinas, lorenzo carelli, nicola petacco, josip orović.

Ship weather routing, which involves suggesting low-emission routes, holds potential for contributing to the decarbonisation of maritime transport. However, including because of a lack of readily deployable open-source and open-language computational models, its quantitative impact has been explored only to a limited extent.

As a response, the graph-search VISIR (discoVerIng Safe and effIcient Routes) model has been refactored in Python, incorporating novel features. For motor vessels, the angle of attack of waves has been considered, while for sailboats the combined effects of wind and sea currents are now accounted for. The velocity composition with currents has been refined, now encompassing leeway as well. Provided that the performance curve is available, no restrictions are imposed on the vessel type. A cartographic projection has been introduced. The graph edges are quickly screened for coast intersection via a K -dimensional tree. A least-CO 2 algorithm in the presence of dynamic graph edge weights has been implemented and validated, proving a quasi-linear computational performance. The software suite's modularity has been significantly improved, alongside a thorough validation against various benchmarks. For the visualisation of the dynamic environmental fields along the route, isochrone-bounded sectors have been introduced.

The resulting VISIR-2 model has been employed in numerical experiments within the Mediterranean Sea for the entirety of 2022, utilising meteo-oceanographic analysis fields. For a 125 m long ferry, the percentage saving of overall CO 2 expenditure follows a bi-exponential distribution. Routes with a carbon dioxide saving of at least 2 % with respect to the least-distance route were found for prevailing beam or head seas. Two-digit savings, up to 49 %, were possible for about 10 d in a year. In the case of an 11 m sailboat, time savings increased with the extent of path elongation, particularly during upwind sailing. The sailboat's routes were made approximately 2.4 % faster due to optimisation, with the potential for an additional 0.8 % in savings by factoring in currents.

VISIR-2 serves as an integrative model, uniting expertise from meteorology, oceanography, ocean engineering, and computer science, to evaluate the influence of ship routing on decarbonisation efforts within the shipping industry.

  • Article (PDF, 8420 KB)
  • Companion paper 1
  • Companion paper 2
  • Supplement (12136 KB)
  • Article (8420 KB)
  • Full-text XML

Mendeley

Mannarini, G., Salinas, M. L., Carelli, L., Petacco, N., and Orović, J.: VISIR-2: ship weather routing in Python, Geosci. Model Dev., 17, 4355–4382, https://doi.org/10.5194/gmd-17-4355-2024, 2024.

As climate change, with its unambiguous attribution to anthropogenic activities, rapidly unfolds ( IPCC ,  2023 ) , the causal roles played by various sectors of the economy, as well as the possibilities for mitigation, are becoming more evident. This holds true for the shipping sector as well ( IPCC ,  2022 ) , which has begun taking steps to reduce its carbon footprint. The International Maritime Organization (IMO) adopted an initial decarbonisation strategy in 2018 ( IMO ,  2018 a ) , which was later revised in 2023. The new ambition is to achieve complete decarbonisation by mid-century, addressing all greenhouse gas (GHG) emissions, with a partial uptake of near-zero GHG technology as early as 2030 ( IMO ,  2023 ) . While no new measures have been adopted yet, the revised strategy is expected to boost efforts to increase the energy efficiency of shipping in the short term ( Smith and Shaw ,  2023 ) . In line with the European Green Deal, the European Union has adopted new rules to include various GHG (carbon dioxide, methane, and nitrous oxide) emissions from shipping in its Emissions Trading System (EU-ETS), starting from 2024 ( https://climate.ec.europa.eu/eu-action/transport-emissions/reducing-emissions-shipping-sector_en , last access: 20 May 2024). For the first time ever, this will entail surrendering allowances for GHG emissions from vessels as well.

Zero-emission bunker fuels are projected to cost significantly more than present-day fossil fuels ( Al-Aboosi et al. ,  2021 ; Svanberg et al. ,  2018 ) . Thus, minimising their use will be crucial for financial sustainability. This necessitates energy savings through efficient use, achieved via both technical (e.g. wind-assisted propulsion systems or WAPSs) and operational measures (e.g. speed reduction and ship weather routing). According to the “CE-Ship” model, a GHG emissions model for the shipping sector, a global reduction in GHG emissions by 2030 by up to 47 % relative to 2008 levels could be feasible through a combination of operational measures, technical innovations, and the use of near-zero-GHG fuels ( Faber et al. ,  2023 ) . A separate study focusing on the European fleet estimates that a reduction in sailing speed alone could potentially lead to a 4 %–27 % emission reduction, while combining technical and operational measures might provide an additional 3 %–28 % reduction ( Bullock et al. ,  2020 ) . The impact of speed optimisation on emissions varies significantly, with potential percentage savings ranging from a median of 20 % to as high as 80 %, depending on factors such as the actual route, meteorological and marine conditions, and the vessel type ( Bouman et al. ,  2017 ) . In that paper, while cases are reported of up to 50 % savings, the role of weather routing was generally assessed to be lower than 10 %.

The variability in percentage savings reported in the literature can be attributed to the diversity of routes considered, the specific weather conditions, and the types of vessels analysed. Additionally, reviews often use a wide range of bibliographic sources, including grey literature, company technical reports, white papers, and works that fail to address the actual meteorological and marine conditions.

The VISIR (discoVerIng Safe and effIcient Routes, pronunciation: /vi′zi:r/) ship weather routing model was designed to objectively assess the potential impact of oceanographic and meteorological information on the safety and efficiency of navigation. So far, two versions of the model have been released (VISIR-1.a – Mannarini et al. ,  2016 a , and VISIR-1.b – Mannarini and Carelli ,  2019 a ). However, the use of a proprietary coding language (MATLAB) may hinder its further adoption. Also, the experience with VISIR-1 suggested the need to enhance the modularity of the package and implement other best practices of scientific coding, as recommended in Wilson et al. ( 2014 ) . Another area where innovation seemed possible was the development of a comprehensive framework to perform weather routing for both motor vessels and sailboats. While some aspects of this requirement were covered through a more modular approach, it also involved rethinking how to utilise environmental fields such as waves, currents, and wind. Furthermore, while the carbon intensity savings of least-time routes were already estimated via VISIR-1.b, a dedicated algorithm for the direct computation of least-CO 2 routes was lacking.

To address all these requirements, we designed, coded, tested, and conducted extensive numerical experiments with the VISIR-2 model ( Salinas et al. ,  2024 a ) . VISIR-2 is a Python-coded software, inheriting from VISIR-1 the fact that it is based on a graph-search method. However, VISIR-2 is a completely new model, leveraging the previous experience while also offering many new solutions and capabilities. Part of the validation process made use of its ancestor model VISIR-1. Computational performance has been enhanced, and efforts have been made to improve usability. In view of use for routing of WAPS vessels, we have developed a unified modelling framework, accounting for involuntary speed loss in waves, advection via ocean currents, thrust, and leeway from wind. A novel algorithm for finding the least-CO 2 routes has been devised, building upon Dijkstra's original method. The visualisation of dynamic information along the route has been further improved using isochrone-bounded sectors. VISIR-2 features are thoroughly described in this paper, along with some case studies and suggestions for possible development lines in the future.

The VISIR-2 model enabled systematic assessment of CO 2 savings deriving from optimal use of meteo-oceanographic information in the voyage planning process. Differently from most of the existing works cited above, the emissions could clearly be related to the significant wave height, relative angle of waves, and also engine load factor. This is discussed further in Sect.  6.1 . Ocean currents can be added to the optimisation, providing more realistic figures for the emission savings.

VISIR-2 is a numerical model well-suited for both academic and technical communities and facilitating the exploration and quantification of ship routing's potential for operational decarbonisation. In the European Union, there may be a need for independent verification of emissions reported in the monitoring, reporting, and verifying (MRV) system ( https://www.emsa.europa.eu/thetis-mrv.html , last access: 20 May 2024). Utilising baseline emissions computed through a weather routing model could enhance the accuracy and reliability of this verification process. Additionally, the incorporation of shipping into the EU-ETS intensifies the importance of minimising GHG emissions. Internationally, even with the adoption of zero- or low-carbon fuels encouraged by the recent update of the IMO's strategy, it remains critical to save these fuels as much as possible. Therefore, VISIR-2 could potentially serve as a valuable tool for saving both fuel and allowances.

The remainder of this paper includes a literature investigation in Sect.  1.1 followed by an in-depth presentation of the innovations introduced by VISIR-2 in Sect.  2 . Subsequently, the model validation is discussed in Sect.  3 and its performance is assessed in Sect.  4 . Several case studies in the Mediterranean Sea follow (Sect.  5 ). The results of the CO 2 emission percentage savings, some potential use cases, and an outlook on possible developments of VISIR-2 are discussed in Sect.  6 . Finally, the conclusions are presented in Sect.  7 . The Appendix contains technical information regarding the computation of the angle of attack between ships' heading and course (Appendix  A ), as well as details about the neural network employed to identify the vessel performance curves (Appendix  B ).

1.1  Literature review on weather routing

This compact review of systems for ship weather routing will be limited to web applications (Sect.  1.1.1 ) and peer-reviewed research papers (Sect.  1.1.2 ). It is further restricted to the freely available versions of desktop applications, while the selection of papers is meant to update the wider reviews already provided in Mannarini et al. ( 2016 a ) and Mannarini and Carelli ( 2019 b ) . A critical gap analysis (Sect.  1.1.3 ) completes this subsection.

1.1.1  Web applications

FastSeas ( https://fastseas.com/ , last access: 20 May 2024) is a weather routing tool for sailboats, with editable polars and the possibility of considering a motor propulsion. Wind forecasts are taken from the National Oceanic and Atmospheric Administration Global Forecast System (NOAA GFS) model and ocean surface currents from NOAA Ocean Surface Current Analyses Real-time (OSCAR). The tool makes use of Windy imagery, a free choice of endpoints is offered, departure time can vary between the present and a few days in the future, and the voyage plan is exportable in various formats.

The Avalon web router ( https://www.webrouter.avalon-routing.com/compute-route , last access: 20 May 2024) provides a coastal weather routing service for sailboats within subregions of France, the United Kingdom, and the United States. It offers a choice among tens of sailboats, with the option to also consider a motor-assisted propulsion. Hourly departure dates within a couple of days are allowed, and ocean weather along the routes is provided in tabular form.

GUTTA-VISIR ( https://gutta-visir.eu , last access: 20 May 2024) is a weather routing tool for a specific ferry developed in the frame of the “savinG fUel and emissions from mariTime Transport in the Adriatic region” (GUTTA) project. It provides both least-time and least-CO 2 routes between several ports of call. It makes use of operational wave and current forecast fields from the Copernicus Marine Environment Monitoring Service (CMEMS). The route departure date and time and the engine load can be varied. Waves, currents, or isolines can be rendered along with the routes, which can be exported.

OpenCPN ( https://opencpn.org/ , last access: 20 May 2024) is a comprehensive open-source platform, including a weather routing tool for sailboats. The product name originates from “Open-source Chart Plotter Navigation”. The vessel performance curves are represented via polars, and forecast data in GRIB format or a climatology can be used. Nautical charts can be downloaded and integrated into the graphical user interface. The programming language is C++, and a velocity composition with currents is accounted for. A detailed documentation of the numerical methods used is lacking though.

1.1.2  Research papers

A review of ship weather routing methods and applications was provided by Zis et al. ( 2020 ) . Several routing methods such as the isochrone method, dynamic programming, calculus of variations, and pathfinding algorithms were summarised before a taxonomy of related literature was proposed. The authors made the point that the wide range of emission savings reported in the literature might in future be constrained via defining a baseline case; providing benchmark instances; and performing sensitivity analyses, e.g. on the resolution of the environmental data used.

A specific weather routing model was documented by Vettor and Guedes Soares ( 2016 ) . It integrates advanced seakeeping and propulsion modelling with multi-objective (fuel consumption, duration, and safety) optimisation. An evolutionary algorithm was used, with initialisation from both random solutions and single-objective routes from a modified Dijkstra's algorithm. Safety constraints were considered via probabilities of exceeding thresholds for slamming, green water, or vertical acceleration. A specific strategy was proposed to rank solutions within a Pareto frontier.

A stochastic routing problem was addressed in Tagliaferri et al. ( 2014 ) . A single upwind leg of a yacht race is considered, with the wind direction being the stochastic variable. The vessel was represented in terms of polars, and the optimal route was computed via dynamic programming. The skipper's risk propensity was modelled via a specific preference on the wind transition matrices. This way it was shown how the risk attitude affects the chance to win a race.

Ladany and Levi ( 2017 ) developed a dynamic-programming approach to sailboat routing which accounts for the tacking time. The latter was assumed to be proportional to the amplitude of the course change. Furthermore, a sensitivity analysis was conducted, considering both the uncertainty in wind direction and the magnitude of the discretisation step in the numerical solution.

Sidoti et al. ( 2023 ) provided a consistent framework for a dynamic-programming approach for sailboats, considering both leeway and currents. In order to constrain the course of the boat on the available edges on the numerical grid, an iterative scheme was adopted. Case studies with NAVGEM winds and global HYCOM currents were carried out in a region across the Gulf Stream. The results without leeway were validated versus OpenCPN.

The impact of stochastic uncertainty on WAPS ships was addressed by Mason et al. ( 2023 b ) . A dynamic-programming technique was used, and “a priori” routing (whereby information available at the start of the journey only is used) was distinguished from “adaptive” routing (whereby the optimum solution is updated based on information that becomes available every 24  h along a journey). The latter strategy is shown, for voyages lasting several days, to be more robust with respect to the unavoidable stochastic uncertainty in the forecasts.

1.1.3  Knowledge gap

A few open web applications exist, mainly for sailboats and with limited insight into their numerical methods. Case study results from weather routing systems developed in academia have been published, but (with the exception of Mason et al. ,  2023 b ) no systematic assessment of CO 2 savings has been provided. Furthermore, no related software has been disclosed in any case. The OpenCPN package lacks both a peer-reviewed publication and documentation of the methods implemented. A prevalence of dynamic-programming approaches is noted, especially for web applications, with the graph-search method being used in research papers only. The tools focus either on sailboats (with or without a motor) or on motor vessels. When both are available (such as in FastSeas), the motor vessel is described in terms of polars.

From this assessment, the lack of an open-source and well-documented ship weather routing model, for both motor vessels and sailboats, with flexible characterisation of vessel performance appears as a gap which the present work aims to close.

This section includes a revision of the vessel kinematics of VISIR, as given in Sect.  2.1 ; changes in the graph generation procedure and in the use of static environmental fields in Sect.  2.2 ; updates to the computation of graph edge weights in Sect.  2.3 ; an additional optimisation objective in the shortest-path algorithm in Sect.  2.4 ; new vessel performance models in Sect.  2.5 ; innovative visualisation capabilities in Sect.  2.6 ; and a more modular structure of the software package, presented in Sect.  2.7 . Further technical details of the VISIR-2 code are presented in the software manual, provided along with its online repository ( Salinas et al. ,  2024 a ) .

2.1  Kinematics

For a graph-search model such as VISIR to deal with waves, currents, and wind for various vessel types, several updates to its approach for velocity composition were needed. They included both generalisations and use of new quantities, addressed in this subsection, as well as a new numerical solution, addressed in Appendix  A .

As in Mannarini and Carelli ( 2019 b ) , the kinematics of VISIR-2 is based on both the principle of superposition of velocities and the discretised sailing directions existing on a graph. However, while previously the vessel's speed over ground (SOG) was obtained from the magnitude of the vector sum of speed through water ( T   =  STW t ^ ) and ocean current ( w ), we show here that, more generally, SOG is the magnitude of a vector G   =  SOG e ^ , being the sum of the forward speed F   =   F h ^ and an effective current ω , and both will be defined in the following. In the absence of leeway, the F and T vectors are identical and ω = w , so the newer approach encompasses the previous one.

Making reference to Fig.  1 , the use of a graph constrains the vessel's course over ground to be along e ^ , being the orientation of one of the graph's arcs. Thus, any cross component of velocity or along a o ^ versor such that e ^ ⋅ o ^ = 0 must be null.

https://gmd.copernicus.org/articles/17/4355/2024/gmd-17-4355-2024-f01

Figure 1 Angular configuration with ( δ = - 27 °, γ i = - 109 °), resulting in ϵ = + 1 . The dark-grey area represents the ship hull, while the light-grey-shaded area denotes the no-go zone for α 0 =25 ° . Clockwise-oriented arcs indicate positive angles, and filled circles at line ends denote the meteorological (“from”) convention.

This implies that, to balance the cross flow from the currents, the vessel must head into a direction h ^ slightly different from the course e ^ . In Mannarini and Carelli ( 2019 b ) , such an angle of attack was defined as

where for both ψ h (heading, or HDG) and ψ e (course over ground, or COG) a nautical convention is used (due north, to direction). That framework is here generalised to also deal with the vector nature of some environmental fields, such as waves or wind. Using a meteorological convention (due north, from direction) for both the ψ a (waves) and ψ i (wind) directions, we here introduce the δ f angles, defined as

where γ f = ψ f - ψ e constitutes the relative angle between the f environmental field and the ship's course. f = a for waves and f = i for wind. In computing angular differences, their convention should be considered (see the angular_utils.py function in the VISIR-2 code). Thus, δ f =0 whenever the ship heads in the direction from which the field comes, and γ f =0 if her course is in such a direction.

Furthermore, we here define leeway as a motion, caused by the wind, transversal to the ship's heading. From the geometry shown in Fig.  1 , the oriented direction of leeway ψ L is given by

where the ⌊⋅⌋ delimiters indicate the floor function. Thus, ϵ is positive for δ i in the [0,180 ° ] range and flips every 180 ° of the argument. This is not the sole possible definition of leeway. For instance, in Breivik and Allen ( 2008 ) a distinction between the downwind and crosswind component of leeway is made. However, the present definition is consistent with the subsequent data of vessel performance (Sect.  2.5.2 ).

Upon expressing the magnitudes F of the vessel's forward velocity and L of leeway velocity as

with wind magnitude V i , significant wave height H s , and engine load χ , a leeway angle, being the ship's heading change between the F and T vectors, can be defined as

The above-introduced α L is not a constant but depends on both wind magnitude V i and the module of the relative direction, | δ i | . Also, from Fig.  1 , it is seen that F   =  STW  ⋅cos  α L . Thus, in the absence of leeway ( α L =0 ), one retrieves the identity of F and STW, which was an implicit assumption made in Mannarini and Carelli ( 2019 b ) .

Equations ( 5a ) and ( 5b ) comprise a major innovation with respect to the formalism of Mannarini and Carelli ( 2019 b ) , as an angular dependence in the performance curve is also introduced in VISIR for motor vessels for the first time (Sect.  2.5 ). Equation ( 5a ) includes dependencies on both wind and waves. Furthermore, a possible dependency on χ , the fractional engine load (or any other propulsion parameter), is highlighted here.

Within this formalism, if the vessel is a sailboat (or rather a motor vessel making use of a WAPS), just one additional condition should be considered. That is, given the wind-magnitude-dependent no-go angle α 0 ( V i ) , upwind navigation is not permitted, or

Now, given a water flow expressed by the vector

and making reference to Fig.  1 , the flow projections along ( e ^ ) and across ( o ^ ) the vehicle course are, respectively,

where for the ocean flow direction ψ w the nautical convention is also used.

In analogy to Eqs. ( 9a ) and ( 9b ) and also using nautical convention for ψ L , the along- and cross-course projections of the leeway are given by

The simple relations on the right-hand side (r.h.s.) of Eqs. ( 10a ) and ( 10b ) follow from the similitude of the red- and green-shaded triangles in Fig.  1 . As δ is typically a small angle (cf. Appendix  A ), it is apparent that the cross component of the leeway, w ⊥ ( L ) , is the dominant one. Its sign is such that it is always downwind; see Fig.  1 . If relevant, the Stokes drift ( van den Bremer and Breivik ,  2018 ) could be treated akin to an ocean current, and one would obtain for its projections a couple of equations formally identical to Eqs. ( 9a ) and ( 9b ).

Finally, the components of the effective flow ω advecting the vessel are

Due to Eqs. ( 10a ) and ( 10b ), both ω ∥ and ω ⊥ are functions of δ . We recall that the “cross” and “along” specifications refer to vessel course ψ e , differing from vessel heading by the δ angle.

The graphical construction in Fig.  1 makes it clear that G   =  SOG e ^ equals T + w or F + ω . Using the latter equality, together with the course assignment condition, and projecting along both e ^ and o ^ , two scalar equations are obtained, namely

Equations ( 12a ) and ( 12b ) are formally identical to those found in Mannarini and Carelli ( 2019 b ) in the presence of ocean currents only. This fact supports the interpretation of ω as an effective current.

However, Eqs. ( 12a ) and ( 12b ) alone are no more sufficient to determine the ocean current vector w . In fact, it is mingled with the effect of wind through leeway to form the effective flow ω (Eqs.  11a , 11b ). This is why, in the presence of strong winds, reconstruction of ocean currents from data of COG and HDG via a naive inversion of Eqs. ( 12a ) and ( 12b ) is challenging. This was indeed found by Le Goff et al. ( 2021 ) using automatic identification system (AIS) data across the Agulhas Current.

As it reduces the ship's speed available along its course (Eq.  12a ), the angle of attack δ plays a pivotal role in determining SOG. However, in the presence of an angle-dependent vessel speed (Eq.  5a ), δ is no longer given by a simple algebraic equation corresponding to Eq. ( 12b ) as in Mannarini and Carelli ( 2019 b ) but by a transcendental one:

In fact, due to Eq. ( 2 ), the r.h.s. of Eq. ( 13 ) depends both explicitly and implicitly on δ . Just in the limiting case of null currents, Eqs. ( 6 ), ( 10b ), and ( 12b ) collectively imply that

However, in general, the actual value of the forward speed F is only determined once the δ angle is retrieved from Eq. ( 13 ). To our knowledge, the transcendental nature of the equation defining δ had not been pointed out previously. Furthermore, in VISIR-2 an efficient numerical approximation for its solution is provided; see Appendix  A . This is also a novelty with practical benefits for the development of efficient operational services based on VISIR-2.

We note that Eq. ( 13 ) holds if and only if

Should this not be the case, the vessels' forward speed would not balance the effective drift.

As F is always non-negative, Eq. ( 13 ) implies that sgn ( δ ) = sgn ( ω ⊥ ) . In particular, in the case of an effective cross flow ω ⊥ bearing, as in Fig.  1 , to starboard, an anticlockwise change in vehicle heading ( δ <0 ) is needed for keeping course (note o ^ versor's orientation in Fig.  1 ).

Equations ( 12a ) and ( 12b ) can be solved for the speed over ground (SOG), which reads

According to Eq. ( 16 ), the cross flow ω ⊥ always reduces SOG, as part of vehicle momentum must be spent balancing the drift. The along-edge flow ω ∥ (or “effective drag”) may instead either increase or decrease SOG.

Finally, given that G = d x / d t , by taking the module of the left side, and approximating the r.h.s. with its finite-difference quotient, the graph edge weight δ t is computed as

where δ x is the edge length and SOG is given by Eq. ( 16 ). As the environmental fields determining SOG are both space and time dependent, the weights δ t are computed via the specific interpolation procedures in Sect.  2.3 and the shortest paths via the algorithms provided in Sect.  2.4 .

From Eq. ( 17 ), it follows that the condition

should be checked in case the specific graph-search method used does not allow for use of negative edge weights (as is the case for Dijkstra's algorithm; cf.  Bertsekas ,  1998 ). Violation of Eq. ( 18 ) may occur in the presence of a strong counter-flow ω ∥ along a specific graph edge, whose weight must correspondingly be set to not a number.

The CO 2 emissions along a graph edge are given by

where Γ = Γ ( | δ i | , V i ; | δ a | , H s , χ ) is the CO 2 emission rate of the specific vessel in the presence of the actual meteo-marine conditions. Both δ t and δ CO 2 are used in the least-CO 2 algorithm introduced in Sect.  2.4 .

2.2  Graph generation

Graph preparation is crucial for any graph-search method. Indeed, graph edges represent potential route legs. Therefore, the specific edges included within the graph directly influence the route topology. In addition, as will be shown in Sect.  2.3.2 , the length of edges affects the environmental field value represented by each edge. On the other hand, graph nodes determine the accessible locations within the domain. Therefore, they must be selected with consideration of both the presence of landmasses and shallow waters.

The structure of the mesh is also the most fundamental difference between a graph-search method (such as Dijkstra's or A * ) and dynamic programming. Indeed, a dynamic-programming problem can be transformed into a shortest-path problem on a graph ( Bertsekas ,  1998 , Sect. 2.1) . In the former, the nodes are organised along sections of variable amplitude corresponding to stages. In the latter, nodes can uniformly cover the entire domain. However, for both dynamic programming ( Mason et al. ,  2023 b ) and graph methods ( Mannarini et al. ,  2019 b ) , the number of edges significantly impacts the computational cost of computing a shortest path.

To efficiently address all these aspects, VISIR-2's graph preparation incorporates several updates compared to its predecessor, VISIR-1b, as outlined in the following sub-sections.

https://gmd.copernicus.org/articles/17/4355/2024/gmd-17-4355-2024-f02

Figure 2 Graph stencil for ν =4 : (a)  grid in spherical coordinates with Δ x resolution along both latitude and longitude axes; (b)  Mercator projection, with different resolutions along y or x , and graph edges (thick black and dashed grey lines) and angles (light blue) relative to due north. The y spacing is shown here as constant but, over a large latitudinal range, does vary. In VISIR-2, just the N q 1 ( ν ) dark-grey nodes (cf. Eq.  20 and Table  1 ) are connected to the origin, while, in VISIR-1, all ν ( ν +1) dark- or light-grey nodes were connected.

2.2.1  Cartographic projection

The nautical navigation purpose of a ship routing model necessitates the provision of both length and course information for each route leg. On the other hand, environmental fields used to compute a ship's SOG (Eq.  16 ) are typically provided as a matrix of values in spherical coordinates (latitude and longitude, similar to the fields used in Sect.  5.1 ). To address these aspects, VISIR-2 introduces a projection feature, which was overlooked in both VISIR-1.a and VISIR-1.b. The Mercator projection was chosen for its capacity to depict constant bearing lines as straight lines ( Feeman ,  2002 ) . The implementation was carried out using the pyproj library, which was employed to convert spherical coordinates on the WGS 84 (World Geodetic System 1984) ellipsoid into a Mercator projection, with the Equator serving as the standard parallel. For visualisation purposes, both the Matplotlib and cartopy libraries were utilised.

2.2.2  Edge direction

Leg courses of a ship route originate from graph edge directions. To determine them, we consider the Cartesian components of the edges in a projected space. As seen from Fig.  2 , this approach results in smaller angles relative to due north compared to using an unprojected graph. For the graph ( ν , Δ x ) values and average latitude of the case studies considered in this paper (Sect.  5 ), the maximum error between an unprojected graph and a Mercator projection would be about 5° (cf. Table  1 ). However, this angle critically impacts vessels like sailboats, whose performance hinges on environmental field orientation. Additionally, at higher latitudes, the courses tend to cluster along meridional directions. To achieve a more isotropic representation of courses, constructing the graph as a regular mesh in the projected space would be needed, which is left for future refinements of VISIR-2.

For a given sea domain, a graph is typically computed once and subsequently utilised for numerous different routes. However, in VISIR-1, the edge direction was recalculated every time a graph was utilised. In VISIR-2, the edge direction is computed just once, during graph generation, after which it is added to a companion file of the graph ( edge_orientation ). In the definition of the edge direction, the nautical convention (due north, to direction) is used in VISIR-2 graphs.

Finally it should be noted that in a directed graph, such as VISIR-2's, edge orientation also matters. Each edge acts as an arrow, conveying flow from “tail” to “head” nodes. Edge orientation refers to the assignment of the head or tail of an edge. Orientation holds a key to understanding vessel performance curves, explored further in Sect.  2.5 .

2.2.3  Quasi-collinear edges

A further innovation regarding the graph involves an edge pruning procedure. This eliminates redundant edges that carry very similar information. Indeed, some edges have the same ratio of horizontal to vertical grid hops (see the possible_hops() function). Examples of these edges are the solid and dashed arrows in Fig.  2 b. When the grid step size and the number of hops are not too large, these edges point to nearly the same angle relative to north. However, starting from an equidistant grid in spherical coordinates, the vertical spacing in Mercator projection is uneven. Thus, the directions of those edges are not exactly the same, and we call such edges “quasi-collinear”. In VISIR-2, only the shortest one among these quasi-collinear edges is retained. This corresponds to the solid arrows in Fig.  2 b. This reduces the number N q 1 of edges within a single quadrant to

where φ is Euler's totient function and ν the maximum number of hops from a given node of the graph. Thus, the quantity right of the inequality represents the total number of edges of a quadrant, including quasi-collinear ones. Using Eq. ( 20 ), at ν =4 already more than one-third of all edges are pruned and, at ν =10 , nearly half of them are (cf. Table  1 ).

Table 1 Edge count and minimum angle with due north. The total number of edges in the first quadrant is ν ( ν +1) , and the count of non-collinear edges is N q 1 from Eq. ( 20 ). For the order of connectivity ν , the angle in the unprojected graph is given by Δ θ = arcsin ( 1 / ν ) , regardless of latitude and grid resolution. Using a Mercator projection, at a latitude of L ° and for Δ x = D °, the angle is given by Δ θ D ( L ) .

and assignment operator in python

Download Print Version | Download XLSX

This benefits both the computer memory allocation and the computing time for the shortest path. The latter is linear in the number of edges; cf.  Bertsekas ( 1998 , Sect. 2.4.5) . A further benefit of pruning quasi-collinear edges is a more faithful representation of the environmental conditions. In fact, the environmental field's values at the graph nodes are used for estimating the edge weights (see Sect.  2.3 ). Thus, keeping just shorter edges avoids using less spatially resolved information.

https://gmd.copernicus.org/articles/17/4355/2024/gmd-17-4355-2024-f03

Figure 3 Bathymetry field from EMODnet represented in shades of grey, with contour lines at depths at z =0   m and z = T , where T =7   m is the vessel draught. Additionally, the GSHHG shoreline at two different spatial resolutions is included.

2.2.4  Bathymetry and draught

The minimal safety requirement is that navigation does not occur in shallow waters. This corresponds to the condition that vessel draught T does not exceed sea depth z at all graph edges used for the route computations. This is equivalent to a positive under keel clearance (UKC) of z − T . As explained later in Sect.  2.3.2 , this can be checked by either evaluating the average UKC at the two edge nodes or interpolating it at the edge barycentre.

However, for a specific edge, UKC could still be positive and the edge cross the shoreline. This is avoided in VISIR by checking for mutual edge–shoreline crossings. Given the burden of this process, in VISIR-1b a procedure for restricting the check to inshore edges was introduced. In VISIR-2, as envisioned in Mannarini and Carelli ( 2019 b , Appendix C) , the process of searching for intersections is carried out using a K -dimensional tree (KDT; Bentley ,  1975 ; Maneewongvatana and Mount ,  1999 ). This is a means of indexing the graph edges via a spatial data structure which can effectively be queried for both nearest neighbours (coast proximity of nodes) and range queries (coast intersection of edges). The scipy.spatial.KDTree implementation was used ( https://docs.scipy.org/doc/scipy/reference/ , last access: 20 May 2024). Use of an advanced data structure in the graph is also a novelty of VISIR-2.

Various bathymetric databases can be used by VISIR-2. For European seas, the EMODnet dataset ( https://portal.emodnet-bathymetry.eu/ , last access: 20 May 2024) ( 1 / 16  arcmin resolution or about 116  m ) was used while, for global coverage, GEBCO_2022 ( https://www.gebco.net/data_and_products/gridded_bathymetry_data/ , last access: 20 May 2024) (15 arcsec resolution or about 463  m ) is available.

2.2.5  Shoreline

The bathymetry dataset, if detailed enough, can even be used for deriving an approximation of the shoreline. From Fig.  3 it is seen that a “pseudo-shoreline” derived from the UKC  =  0 contour line of a bathymetry that is fine enough (the EMODnet one) can effectively approximate an official shoreline (the GSHHG ( https://www.ngdc.noaa.gov/mgg/shorelines/ , last access: 20 May 2024) one, at the “high”-type resolution of 200  m ).

Such a pseudo-shoreline is the one used in VISIR-2 for checking the edge crossing condition specified in Sect.  2.2.4 .

2.3  Edge weights

For computing shortest paths on a graph, its edge weights are preliminarily needed. Due to Eqs. ( 16 ) and ( 5a )–( 5b ), they depend on both space- and time-dependent environmental fields, whose information has to be remapped to the numerical grids of VISIR-2. This is done in a partly differently way than in VISIR-1, providing users with improved flexibility and control over numerical fields. These novel options are documented in what follows.

https://gmd.copernicus.org/articles/17/4355/2024/gmd-17-4355-2024-f04

Figure 4 Temporal grid of VISIR-2. The upper horizontal axis ( t ) represents the coarse and uneven time resolution of the original environmental field. The lower horizontal axis corresponds to the fine and even time grid with resolution Δ τ to which it is remapped.

2.3.1  Temporal interpolation

The time at which edge weights are evaluated is key to the outcome of the routing algorithm. In Mannarini et al. ( 2019 b ) , to improve on the coarse time resolution of the environmental field, a linear interpolation in time of the edge weight was introduced (“Tint  =1 ” option in Fig.  4 ). In VISIR-2, instead, the environmental field values (grey dots) are preliminarily interpolated in time on a finer grid with Δ τ spacing (“Tint  =2 ” or blue dots). Then, the edge weight at the nearest available time step ( np.floor function used, corresponding to the blue segments) is selected.

2.3.2  Spatial interpolation

The numerical environmental field and the graph grid may possess varying resolutions and projections. Even if they were identical, the grid nodes might still be staggered. Moreover, it is necessary to establish a method for assigning the field values to the graph edges. For all these reasons, spatial interpolation of the environmental fields is essential.

https://gmd.copernicus.org/articles/17/4355/2024/gmd-17-4355-2024-f05

Figure 5 Spatial interpolation in VISIR-2. (a)  The squares represent grid nodes of the environmental field φ ( x ) , and the filled circles represent graph grid nodes. A graph edge is depicted as a magenta segment. (b)  Transect of (a)  along the edge direction e ^ , with the interpolator of φ as a solid grey line. The (0, 1) subscripts refer to the value of the Sint parameter, while h and t refer to the edge head and tail, respectively.

VISIR-2 first computes an interpolant using the scipy.interpolate.interp2d method. Then, to assign a representative value of the φ field on an edge, two options are available, which are depicted in Fig.  5 . In the first one or “Sint  =0 ”, an average between the edge head and tail values is computed, φ 0 = ( φ h + φ t ) / 2 . In the second one or “Sint  =1 ”, the field interpolator is evaluated at the location of the edge barycentre, φ 1 = φ ( x h + x t / 2 ) . As the field is generally nonlinear, this leads to different outcomes.

The two interpolation schemes were tested with various non-convex functions, and some results are reported in Sect. S0 of the Supplement. We observed that both options converge to a common value as the ( 1 / Δ x ) resolution of the graph grid increases. Thus, both options benefit from pruning collinear edges (Sect.  2.2.3 ), as they remove some longer edges from the graph, but neither demonstrates consistent superiority over the other in terms of fidelity.

However, setting Sint  =0 results in higher computational efficiency. This is because the interpolator is applied at each node with Sint  =0 , whereas it is applied at each edge with Sint  =1 . Given that the number of edges exceeds the number of nodes by a factor defined by Eq. ( 20 ), for the case studies ( 4 ≤ ν ≤ 5 ), the computational time for Sint  =0 was approximately 1 order of magnitude smaller than with Sint  =1 . Therefore, the latter was chosen as the default for VISIR-2.

The resulting edge-representative environmental field value affects the edge delay (Eq.  17 ), consequently impacting the vessel's speed as per Eqs. ( 5a ) and ( 5b ). Hence, a nonlinear relationship exists between the field value and the local sailing speed. Thus, the actual choice of the Sint parameter is not expected to systematically bias the vessel's speed in either direction.

Even before the spatial interpolation is performed, the so-called “sea-over-land” extrapolation is applied to the marine fields. This step, which is needed for filling the gaps in the vicinity of the shoreline, is conceptually performed as in Mannarini et al. ( 2016 a , Fig. 7) and implemented in the seaoverland function.

Since wave direction is a circular periodic quantity, we calculate its average using the circular mean ( https://en.wikipedia.org/wiki/Circular_mean , last access: 20 May 2024) ahead of interpolation. This differs from wind direction, typically given as Cartesian components ( u , v ), which can be interpolated directly.

2.4  Shortest-path algorithms

A major improvement made possible by the Python coding of VISIR-2 is the availability of built-in, advanced data structures such as dictionaries, queues, and heaps. They are key in the efficient implementations of graph-search algorithms ( Bertsekas ,  1998 ) . In particular, as data structures are used, Dijkstra's algorithm worst-case performance can improve from quadratic, 𝒪( N 2 ) , to linear–logarithmic, 𝒪( N log  N ) , where N is the number of graph nodes.

Nonetheless, Dijkstra's original algorithm exclusively accounted for static edge weights ( Dijkstra ,  1959 ) . When dynamic edge weights are present, Orda and Rom ( 1990 ) demonstrated that, in general, there are no computationally efficient algorithms. However, they also showed that, upon incorporating a waiting time at the source node, it is possible to keep the algorithmic complexity of a static problem. Given the assumption that the rate of variation in the edge delay δ t satisfies

an initial waiting time is not even unnecessary. This condition was assumed to hold in Mannarini et al. ( 2016 a ) for implementing a time-dependent Dijkstra's algorithm. That version of the shortest-path algorithm could not be used with an optimisation objective differing from voyage duration. As one aims to compute, for example, least-CO 2 routes, the algorithm requires further generalisation. This has been addressed in VISIR-2 via the pseudo-code provided in both Algorithms  1 and 2 . For its implementation in Python, we made use of a modified version of the single_source_Dijkstra function of the NetworkX Python library. The modification consisted in retrieving an edge weight at a specific time step. This is achieved via Algorithm  2 . In this, the cost.at_time pseudo-function represents a NetworkX method to access the edge weight information.

We note the generality of the pseudo-code with respect to the edge weight type ( w T parameter in both Algorithms  1 and 2 ). This implies that the same algorithm could also be used to compute routes that minimise figures of merit differing from CO 2 , such as different GHG emissions, cumulated passenger comfort indexes, or total amount of underwater radiated noise. This hinges solely on the availability of sufficient physical–chemical information to compute the corresponding edge weight in relation to the environmental conditions experienced by the vessel. A flexible optimisation algorithm is yet another novelty of VISIR-2.

The shortest-distance and the least-time algorithms invoked for both motor vessels and sailboats are identical. Differences occur at the post-processing level only, as different dynamical quantities (related to the marine conditions or the vessel kinematics) have to be evaluated along the optimal paths. Corresponding performance differences are evaluated in Sect. S1 of the Supplement.

Algorithm 1 _DIJKSTRA_TDEP.

Algorithm 2 GET_TIME_INDEX.

2.4.1  Non-FIFO

As previously mentioned, Dijkstra's algorithm can recover the optimal path in the presence of dynamic edge weights if Eq. ( 21 ) is satisfied. For cases where the condition is not met, Orda and Rom ( 1990 ) presented a constructive method for determining a waiting time at the source node. In this case, waiting involves encountering more favourable edge delay values, leading to the computation of a faster path. In other words, employing a first-in–first-out (FIFO) strategy for traversing graph edges may not always be optimal. This is why such a scenario is referred to as “non-FIFO”. We observe that condition Eq. ( 21 ) is violated when a graph edge, which was initially unavailable for navigation, suddenly becomes accessible. While this is a rather infrequent event for motor vessels (in Mannarini and Carelli ,  2019 b , non-FIFO edges were just 10 −6 of all graph edges), it is a more common situation for sailboats navigating in areas where the wind is initially too weak or within the no-go zone (Eq.  7 , Fig.  7 ). Indeed, the unavailability of an edge can be suddenly lifted as the wind strengthens or changes direction. However, under a FIFO hypothesis, the least-time algorithm would not wait for this improvement of the edge delay to occur. Rather, it would look for an alternative path that avoids the forbidden edge, potentially leading to a suboptimal path. In the case study of this paper, such a situation occurred for about 2 × 10 - 3 of the total number of sailboat routes; see Sects.  2.5.2 and S3.2.

2.5  Vessel modelling

At the heart of the VISIR-2 kinematics of Sect.  2.1 are the vessel forward and transversal speed in a seaway, Eqs. ( 5a )–( 5b ). In what follows, such a vessel performance function is also termed a “vessel model”.

In VISIR-1 the forward speed resulted, for motor vessels, from a semi-empirical parameterisation of resistances ( Mannarini et al. ,  2016 a ) and, for sailboats, from polar diagrams ( Mannarini et al. ,  2015 ) . The transversal speed due to leeway was neglected.

In VISIR-2 new vessel models were used, and just two of them are presented in this paper: a ferry and a sailboat. However, any other vessel type can be considered, provided that the corresponding performance curve is utilised in the Navi module (Table  4 , Fig.  8 ). The computational methods used to represent both the ferry and the sailboats are briefly described in Sect.  2.5.1 – 2.5.2 . All methods provide the relevant kinematic quantities and, where applicable, the emission rates in correspondence to discrete values of the environmental variables. Such a “lookup table” (LUT) was then interpolated to provide VISIR-2 with a function to be evaluated in the actual environmental (wave, currents, or wind) conditions. Additional LUTs can be used as well, and the relevant function for this part of the processing is vesselModels_identify.py .

The interpolating function was either a cubic spline (for sailboats) or the outcome of a neural-network-based prediction scheme (for the ferry). The neural network features are provided in Appendix  B . While the neural network generally demonstrated superior performance in fitting the LUTs (see Sect. S2 of the Supplement), it provided unreliable data in extrapolation mode, as shown in Figs.  6 – 7 . In contrast, the spline, when extrapolation was requested, returned the value at the boundary of the input data range.

2.5.1  Ferry

The ferry modelled in VISIR-2 was a medium-size Ro-Pax vessel whose parameters are reported in Table  2 .

Table 2 Principal parameters of the ferry.

and assignment operator in python

1 kn  =  1.852 km h −1 .

A vessel's seakeeping model was used at the ship simulator at the University of Zadar, as documented in Mannarini et al. ( 2021 ) . Therein, additional details about both the simulator and the vessel can be found. The simulator applied a forcing from wind waves of significant wave height H s related to the local wind intensity V i by

This relationship was derived by Farkas et al. ( 2016 ) for the wave climate of the central Adriatic Sea. The simulator then recorded the resulting vessel speed, as well as some propulsion- and emission-related quantities. Leeway could not be considered by the simulator. The post-processed data feed the LUT to then be used for interpolating both STW and the CO 2 emission rate Γ as functions of significant wave height H s , relative wind-wave direction δ a = δ i , and fractional engine load χ . The results are displayed in Fig.  6 .

In a given sea state, the sustained speed is determined by the parameter χ . For head seas ( δ a =0 ° ) STW is seen to decrease with H s . The maximum speed loss varies from about 45 % of the calm water speed at χ =1 to about 70 % at χ =0.7 (Fig.  6 a). For χ =0.7 , the STW sensitivity to H s decreases from head ( δ a =0 °) to following seas ( δ a =180 °, Fig.  6 b). For this specific vessel, the increase in roll motion in beam seas, as discussed in Guedes Soares ( 1990 ) , and its subsequent impact on speed loss do not appear to constitute a relevant factor.

The Γ rate, which is on the order of 1  t  CO 2  h −1 , shows a shallow dependence on H s (Fig.  6 c), while it is much more critically influenced by both χ and δ a (Fig.  6 c, d).

https://gmd.copernicus.org/articles/17/4355/2024/gmd-17-4355-2024-f06

Figure 6 Ferry performance curve: in (a) , STW is shown as a function of significant wave height H s for head seas ( δ a =0 ° ), with engine load χ indicated by the marker colour. In (b) , STW is plotted as a function of δ a at a constant χ =0.7 , with H s represented by the colour variation. The lower panels  (c, d) display the CO 2 emission rate ( Γ ) with similar dependencies to in panels  (a) and (b) . Markers correspond to the LUT values, solid lines represent the spline interpolation, and dotted lines indicate the neural network's output.

2.5.2  Sailboat

Any sailboat described in terms of polars can in principle be used by VISIR-2. For the sake of the case study, a Bénétau First 36.7 was considered. Its hull and rigging features are given in Table  3 .

The modelling of the sailboat STW was carried out by means of the WinDesign velocity prediction program (VPP). The tool was documented in Claughton ( 1999 , 2003 ) and references therein. The VPP is able to perform a four-degrees-of-freedom analysis, taking into account a wide range of semi-empirical hydrodynamic and aerodynamic models. It solves an equilibrium problem by a modified multi-dimensional Newton–Raphson iteration scheme. The analysis considered the added resistance due to waves by means of the so-called “Delft method” based on the Delft Systematic Yacht Hull Series (DSYHS). Besides, the tool allows us to introduce response amplitude operators derived from other techniques as well, such as computational fluid dynamics. The wind-wave relationship was assumed to be given by Eq. ( 22 ). For each wind configuration (i.e. speed and direction), the optimal choice of sail set was considered. The main sail and the jib sail were considered for upwind conditions; otherwise the combination of main sail and spinnaker was used.

Table 3 Principal parameters of the sailboat (First 36.7).

and assignment operator in python

Figure 7 Sailboat performance curve: forward speed F in  (a) and leeway speed L in  (b) are both plotted against the true wind angle δ i . Panel  (c)  shows the leeway angle α L obtained from Eq. ( 6 ). Marker and line colours represent wind magnitude V i . Data start at δ i = α 0 ( V i ) . Markers refer to the LUT, solid lines to spline interpolation, and dotted lines to the neural network's output. The colour bar also reports the LUT's minimum and maximum values printed in blue and red, respectively.

The outcome corresponds to Eqs. ( 5a ) and ( 5b ) and is provided in Fig.  7 . The no-go angle α 0 varies from 27 to 53° as the wind speed increases from 5 to 25  kn . At any true wind angle of attack δ i , the forward speed F increases with wind intensity, especially at lower magnitudes (Fig.  7 a). The peak boat speed is attained for broad reach ( δ i ≈135 °). Leeway magnitude L instead is at its largest for points of sail between the no-go zone ( δ i = α 0 ) and beam reach ( δ i =90 °); see Fig.  7 b. As the point of sail transitions from the no-go zone to running conditions, the leeway angle α L gradually reduces from 6 to 0°. This decrease follows a roughly linear pattern, as depicted in Fig.  7 c.

2.6  Visualisation

Further innovations brought in by VISIR-2 concern the visualisation of the dynamic environmental fields and the use of isolines.

To provide dynamic information via a static picture, the fields are rendered via concentric shells originating at the departure location. The shape of these shells is defined by isochrones. These are lines joining all sea locations which can be reached from the origin upon sailing for a given amount of time. This way, the field is portrayed at the time step the vessel is supposed to be at that location. Isochrones bulge along gradients of a vessel's speed. Such shells represent an evolution of the stripe-wise rendering introduced in VISIR-1.b ( Mannarini and Carelli ,  2019 b , Fig. 5) . The saved temporal dimensional of this plot type allows for its application in creating movies, where each frame corresponds to varying values of another variable, such as the departure date or engine load; see the “Video supplement” of this paper. This visual solution is another novelty introduced by VISIR-2.

In addition to isochrones, lines of equal distance from the route's origin (or “isometres”) and lines of equal quantities of CO 2 emissions (or “isopones”) are also computed. The name isopone is related to energy consumption (the Greek word means “equal effort”), which, for an internal combustion engine, the CO 2 emission is proportional to. Isopones bulge against gradients of emissions. Isometres do not bulge, unless some obstruction (shoals, islands, landmass in general) prevents straight navigation. Given that rendering is on a Mercator map, “straight” refers to a ship's movement along a constant bearing line. Isochrones correspond to the reachability fronts used in a model based on the level set equation (LSE) by Lolla ( 2016 ) .

2.7  Code modularity and portability

Software modularity has been greatly enhanced in VISIR-2. While in VISIR-1 modularity was limited to the graph preparation, which was detached from the main pipeline ( Mannarini et al. ,  2016 a , Fig. 8) , the VISIR-2 code is organised into many more software modules. Their characteristics are given in Table  4 , and the overall model workflow is shown in Fig.  8 .

https://gmd.copernicus.org/articles/17/4355/2024/gmd-17-4355-2024-f08

Figure 8 VISIR-2 workflow. Modules enclosed within thicker frames are intended for direct execution by the end user, while the other modules can be modified for advanced usage. The data flow occurs along the wavy arrow, with routine calls along the dashed line.

Table 4 VISIR-2 modules with their original names, purpose, and references within this paper. Module nos. 1–5 represent the core package and require the visir-venv virtual environment. Module no. 6 runs with visir _ vis-venv.

and assignment operator in python

The modules can be run independently and can optionally save their outputs. Through the immediate availability of products from previously executed modules, this favours research and development activities. For operational applications (such as GUTTA-VISIR) instead, the computational workflow can be streamlined by avoiding the saving of the intermediate results. VISIR-2 module names are Italian words. This is done for enhancing their distinctive capacity; cf.  Wilson et al. ( 2014 ) . More details on the individual modules can be found in the user manual, provided as part of the present release ( Salinas et al. ,  2024 a ) .

A preliminary graphical user interface (GUI) is also available. In the version of VISIR-2 released here, it facilitates the ports' selection from the World Port Index ( https://msi.nga.mil/Publications/WPI , last access: 20 May 2024) database.

VISIR-2 was developed on macOS Ventura (13.x). However, both path parameterisation and the use of virtual environments ensure portability, which was successfully tested for both Ubuntu 22.04.1 LTS and Windows 11, on both personal computers and two distinct high-performance computing (HPC) facilities.

Validating a complex model like VISIR-2 is imperative. The code was developed with specific runs of VISIR-1 as a benchmark. The validation of VISIR-1 involved comparing its outcomes with both analytical and numerical benchmarks and assessing its reliability through extensive utilisation in operational services ( Mannarini et al. ,  2016 b ) .

Previous studies have compared VISIR-1 to analytical benchmarks for both static wave fields (“Cycloid”; Mannarini et al. ,  2016 a ) and dynamic currents (“Techy”; Mannarini and Carelli ,  2019 b ). Here, we present the results of executing the same tests with VISIR-2, at different graph resolutions, as shown in Table  5 . The errors are consistently found to be below 1 %.

Table 5 VISIR-2 route durations compared to analytic oracles (Cycloid and Techy), as referenced in the main text. L 0 and T 0 represent the length scales and timescales, respectively. The oracle durations are denoted by T ( e ) , while those from VISIR-2 are denoted by T * . The percentage mismatch is calculated as d T * = ( T * / T ( e ) ) - 1 .

and assignment operator in python

1 nmi  =  1852 m.

Additionally, in Mannarini et al. ( 2019 b , Table II) , routes computed in dynamic wave fields were compared to the results from a model based on the LSE. For these specific runs of VISIR-2, the benchmarks were taken as LSE simulations at the nearest grid resolution. Notably, VISIR-2 consistently produces shorter-duration routes compared to VISIR-1.b (see Table  6 ).

Table 6 VISIR-2 vs. LSE durations. The relative error d T res * is defined as the discrepancy between T * and LSE at two different grid resolutions 1 / Δ x . Both VISIR-2 and VISIR-1 outcomes are provided.

and assignment operator in python

For both analytical and numerical benchmarks, distinct from the scenario discussed in Sect.  2.2.3 , quasi-collinear edges were retained in the graphs.

During the tests mentioned earlier, the vessel's STW remained unaffected by vector fields. In instances where there was a presence of current vector fields (Techy oracle), they were merely added to STW, without directly impacting it. Therefore, the enhanced capability of VISIR-2 to accommodate angle-dependent vessel performance curves (cf. Eqs.  5a and 5b ) needs to be showcased.

To achieve this objective, the OpenCPN model was utilised. This model can calculate sailboat routes with or without factoring in currents and incorporates shoreline knowledge, though it does not consider bathymetry. For our tests, we provided VISIR-2 with wind and sea current fields identical to those used by OpenCPN (further details are provided in Sect.  5.1 ). Additionally, both models were equipped with the same sailboat polars. However, it is worth noting that OpenCPN does not handle leeway, whereas VISIR-2 can manage it. The VISIR-2 routes were computed on graphs of variable mesh resolution 1 / Δ x and connectivity ν , keeping fixed the “path resolution” parameter Δ P , which was introduced in Mannarini et al. ( 2019 b , Eq. 6) . This condition ensures that the maximum edge length remains approximately constant as the (Δ x , ν ) parameters are varied. Exemplary results are depicted in Fig.  9 , with corresponding metrics provided in Table  7 .

Table 7 VISIR-2 vs. OpenCPN comparison. Durations T * and relative mismatch d T * for the cases shown in Fig.  9 are provided. k =2 and Δ τ =15 min used throughout the numerical experiments.

and assignment operator in python

Figure 9 VISIR-2 routes with wind and currents vs. OpenCPN: graphs of variable resolution, indexed by ν as shown in the legend, with a constant Δ P ∼0.3 °. Field intensity is in grey tones, and the direction is shown as black streamlines. Shell representation with isochrones is in dashed gold lines, and labels are in hours. The OpenCPN solution is plotted as a navy line. Panels  (a) and (b)  refer to the west- and eastbound voyage, respectively.

VISIR-2 routes exhibit topological similarity to OpenCPN routes, yet for upwind sailing, they require a larger amount of tacking (see Fig.  9 a). This discrepancy arises from the limited angular resolution of the graph (cf. Table  1 ). In the absence of currents, this implies a longer sailing time for VISIR-2 with respect to OpenCPN routes, ranging between 1.0 % and 3.4 %. However, as the graph resolution is increased, the route duration decreases. Notably, this reduction plateaus at ν =7 , indicating that such a resolution is optimal for the given path length. This type of comparison addresses the suggestion by Zis et al. ( 2020 ) to investigate the role of resolution in weather routing models. For a more thorough discussion of this particular aspect, please refer to Mannarini et al. ( 2019 b ) .

Downwind routes all divert northwards because of stronger wind there (Fig.  9 b). For these routes, the angular resolution does not pose a limiting factor, and VISIR-2 routes exhibit shorter durations compared to OpenCPN routes. Considering the influence of currents as well, VISIR-2 routes consistently prove to be the faster option, even for upwind sailing.

The disparities in duration between OpenCPN and VISIR-2 routes could be attributed to various factors, including the interpolation method used for the wind field in both space and time and the approach employed to consider currents. Delving into these aspects would necessitate a dedicated investigation, which is beyond the scope of this paper.

Numerical tests have been integrated into the current VISIR-2 release ( Salinas et al. ,  2024 a ) , covering the experiments listed in Tables  5 – 7 and beyond. These tests can be run using the Validazioni module.

The computational performance of VISIR-2 was evaluated using tests conducted on a single node of the “Juno” HPC facility at the Euro-Mediterranean Center on Climate Change (CMCC). This node was equipped with an Intel Xeon Platinum 8360Y processor, featuring 36 cores, each operating at a clock speed of 2.4 GHz, and boasting a per-node memory of 512 GB. Notably, parallelisation of the cores was not employed for these specific numerical experiments. Subsequently, our discussion here is narrowed down to assessing the performance of the module dedicated to computing optimal routes (“ Tracce ”) in its motor vessel version.

In Fig.  10 , we assess different variants of the shortest-path algorithm: least-distance, least-time, and least-CO 2 procedures. We differentiate between the core of these procedures, which focuses solely on computing the optimal sequence of graph nodes (referred to hereafter as the “Dijkstra” component), and the broader procedure (“total”), which also includes the computation of both marine and vessel dynamical information along the legs of the optimal paths. The spatial interpolation option used in these tests (Sint  =1 of Sect.  2.3.2 ) provides a conservative estimation of computational performance.

The numerical tests utilise the number of degrees of freedom (DOF) for the shortest-path problem as the independent variable. This value is computed as A ⋅ N τ , where A denotes the number of edges and N τ stands for the number of time steps of the fine grid (cf. Fig.  4 ). In the context of a sea-only edge graph, particularly in the case of a large graph (where border effects can safely be neglected), A can be represented as 4⋅ N q 1 ( ν ) , where N q 1 is defined by Eq. ( 20 ). Random edge weights were generated for graphs with ν =10 , resulting in a number of DOFs ranging between 10 5 and 10 9 . Each data point in Fig.  10 represents the average of three identical runs, which helps reduce the impact of fluctuating HPC usage by other users. Additionally, the computational performance of VISIR-2 is compared to that of VISIR-1b, as documented in Mannarini and Carelli ( 2019 b , Table 3, “With T-interp”) .

https://gmd.copernicus.org/articles/17/4355/2024/gmd-17-4355-2024-f10

Figure 10 Profiling of computing time for the Tracce module (motor vessel case). The independent variable is the number of DOFs (#DOF) in the graph. Markers refer to experimental data points and lines to least-square fits. Void markers and dashed lines refer to just Dijkstra's component, while full markers and solid lines refer to the whole of the each routine. The colours refer to the three alternative optimisation objectives, while black is used for VISIR-1.b results.

The primary finding is a confirmation of a power-law performance for all three optimisation objectives of VISIR-2: distance, route duration, and total CO 2 emissions. Remarkably, the curves appear nearly linear for the latter two algorithms (see Table  8 ). Such a scaling is even better than the linear–logarithmic worst-case estimate for Dijkstra's algorithms ( Bertsekas ,  1998 , Sect. 2.3.1) . Furthermore, this is not limited to just the Dijkstra components (as observed in VISIR-1.b) but extends to the entire procedure, encompassing the reconstruction of along-route variables. In addition to this enhanced scaling, VISIR-2 demonstrates an improved absolute computational performance within the explored DOF range. The performance gain is approximately a factor of 10 when compared to VISIR-1.b. This factor should even be larger when using the Sint  =0 interpolation option.

Digging deeper into the details, we observe that the least-distance procedure within VISIR-2, while exclusively dealing with static edge weights, exhibits a less favourable scaling behaviour compared to both the least-time and least-CO 2 procedures. This is attributed to the post-processing phase, wherein along-route information has to be evaluated at the appropriate time step. Further development is needed to improve on this. Additionally, tiny nonlinearities are seen for the smaller number of DOFs. However, as proven by the metrics reported in Table  8 , they do not affect the overall goodness of the power-law fits.

Lastly, it was found that peak memory allocation scales linearly across the entire explored range, averaging about 420  B per DOF. This is about 5 times larger than in VISIR-1b and should be attributed to the NetworkX structures used for graph representation. However, the large memory availability at the HPC facility prevented a possible degradation of performance for the largest numerical experiments due to memory swapping. A reduction in the unit memory allocation by a factor of 2 should be feasible using single-precision floating-point format. Another strategy would involve using alternative graph libraries, such as igraph .

Table 8 Fit coefficients of the T c = a ⋅ DOF b + c regressions for various components of Tracce , motor vessel version. “D” stands for Dijkstra's algorithm only, while “tot” includes the post-processing for reconstructing the voyage. p ( K ) is the p  value for the K coefficient. All data refer to VISIR-2 except the * _ V1b data, which refer to VISIR-1.b.

and assignment operator in python

A more comprehensive outcome of the VISIR-2 code profiling, distinguishing also between the sailboat and the motor vessel version of the Tracce module, is provided in Sect. S1 of the Supplement.

A prior version of VISIR-2 has empowered GUTTA-VISIR operational service, generating several million optimal routes within the Adriatic Sea over the span of a couple of years. In this section, we delve into outcomes stemming from deploying VISIR-2 in different European seas. While the environmental fields are elaborated upon in Sect.  5.1 , the results are given in Sect.  5.2 , distinguishing by ferry and sailboat.

5.1  Environmental fields

The fields used for the case studies include both static and dynamic fields. The only static one was the bathymetry, extracted from the EMODnet product of 2022 ( https://emodnet.ec.europa.eu/en/bathymetry , last access: 20 May 2024). Its spatial resolution was 1 / 16  arcmin. The dynamic fields were the metocean conditions from both the European Centre for Medium-Range Weather Forecasts (ECMWF) and CMEMS. Analysis fields from the ECMWF high-resolution Atmospheric Model, 10 d forecast (Set I – HRES) with 0.1° resolution ( https://www.ecmwf.int/en/forecasts/datasets/set-i#I-i-a_fc , last access: 20 May 2024) were obtained. Both the u10m and v10m variables with 6-hourly resolution were used. From CMEMS, analyses of the sea state, corresponding to the hourly MEDSEA_ANALYSISFORECAST_WAV_006_017 product, and of the sea surface circulation, corresponding to hourly MEDSEA_ANALYSISFORECAST_PHY_006_013, both with 1 / 24 ° spatial resolution, were obtained. The wind-wave fields (vhm0 _ ww, vmdr _ ww) and the Cartesian components (uo, vo) of the sea surface currents were used, respectively. Just for the comparison of VISIR-2 to OpenCPN (see Sect.  3 ), 3-hourly forecast fields from ECMWF (0.4°, https://www.ecmwf.int/en/forecasts/datasets/open-data , last access: 20 May 2024) and 3-hourly Real-Time Ocean Forecast System (RTOFS) forecasts ( 1 / 12 °, https://polar.ncep.noaa.gov/global/about/ , last access: 20 May 2024) for surface currents (p3049 and p3050 variables for U and V , respectively) were used.

The kinematics of VISIR-2 presented in Sect.  2.1 do not limit the use to just surface ocean currents. This was just an initial approximation based on the literature discussed in Mannarini and Carelli ( 2019 b ) . However, recent multi-sensor observations reported in Laxague et al. ( 2018 ) at a specific location in the Gulf of Mexico revealed a significant vertical shear, in both magnitude (by a factor of 2) and direction (by about 90°), within the first 8  m . Numerical ocean models typically resolve this layer; for instance the aforementioned Mediterranean product of CMEMS provides four levels within that depth. These vertically resolved data hold the potential to refine the computation of a ship's advection by the ocean flow. A plausible approach could involve the linear superposition of vessel velocity with a weighted average of the current, also considering the ship's hull geometry.

5.2  Results

To showcase some of the novel features of VISIR-2, we present the outcomes of numerical experiments for both a ferry (as outlined in Sect.  2.5.1 ) and a sailboat (Sect.  2.5.2 ). All the results were generated using the interpolation options Sint  =0 (as elaborated upon in Sect.  2.3.2 ) and Tint  =2 (Sect.  2.3.1 ). These experiments considered the marine and atmospheric conditions prevailing in the Mediterranean Sea during the year 2022. Departures were scheduled daily at 03:00 UTC. The percentage savings ( d Q ) of a given quantity Q (such as the total CO 2 emissions throughout the journey or the duration of sailing) are computed comparing the optimal (“opt”) to the least-distance route (“gdt”):

5.2.1  Ferry

The chosen domain lies at the border between the Provençal Basin and the Ligurian Sea. Its sea state is significantly influenced by the mistral, a cold northwesterly wind that eventually affects much of the Mediterranean region during the winter months. The circulation within the domain is characterised by the southwest-bound Liguro–Provençal current and the associated eddies ( Schroeder and Chiggiato ,  2022 ) .

We conducted numerical experiments using VISIR-2 with a graph resolution given by ( ν , 1 / Δ x ) = ( 4 , 12 / ° ) , resulting in 2768 nodes and 114 836 edges within the selected domain. The time grid resolution was set at Δ τ =30 min and N τ =40 . A single iteration ( k =1 ) of Eq. ( A1 ) was performed. The ferry engine load factor χ was varied to encompass values of 70 %, 80 %, 90 %, and 100 % of the installed engine power. For each day, both route orientations, with and without considering currents, were taken into account. This led to a total of 5840 numerical experiments. The computation time for each route was approximately 4  min , with the edge weight and shortest-path calculations consuming around 30  s .

In Fig.  11 a an illustrative route is shown during a mistral event. As the ferry navigates against the wind, both its speed loss and its CO 2 emission rate reach their maximum levels (cf. Fig.  6 b, d). Consequently, both the least-time and the least-CO 2 algorithms calculate a detour into a calmer sea region where the combined benefits of improved sustained speed and reduced CO 2 emissions compensate for the longer path's costs. The least-CO 2 detour is wider than the least-time one, as the additional duration is compensated for by greater CO 2 savings. Moreover, these detours maximise the benefits from a southbound meander of the Liguro–Provençal current. Both optimal solutions intersect the water flow at points where it is narrowest, minimising the speed loss caused by the crosscurrent (cf. Eq.  16 ). Recessions of the isochrones become apparent starting at 6  h after departure. For this specific departure date and time, the overall reduction in CO 2 emissions, in comparison to the shortest-distance route, exceeds 35 %.

Figure  11 b illustrates that the magnitude of the related spatial diversion is merely intermediate, compared to the rest of 2022. Particularly during the winter months, the prevailing diversion is seen to occur towards the Ligurian Sea. Notably, VISIR-2 even computed a diversion to the east of Corsica, which is documented in Sect. S3.1 of the Supplement. In the “Video supplement” accompanying this paper, all the 2022 routes between Porto Torres and Toulon are rendered, along with relevant environmental data fields.

https://gmd.copernicus.org/articles/17/4355/2024/gmd-17-4355-2024-f11

Figure 11 The ferry's optimal routes between Porto Torres (ITPTO) and Toulon (FRTLN) with both waves and currents: (a)  for the specified departure date and time, the shortest-distance route is shown in blue, the least-time route in red, and the least-CO 2 route in green. The H s field is displayed in shades of grey with black arrows, while the currents are depicted in purple tones with white streamlines. The shortest-path algorithm did not utilise environmental field values within the etched area. Additionally, isochrones of the CO 2 -optimal route are shown at 3-hourly intervals. The engine load was χ =0.7 . (b)  A bundle of all northbound CO 2 -optimal routes (for χ = { 0.7 , 0.8 , 0.9 , 1.0 } ) is presented, with the line colour indicating the departure month.

To delve deeper into the statistical distribution of percentage CO 2 savings defined as in Eq. ( 23 ), Fig.  12 a provides a comparison with both the average significant wave height 〈 H s ( gdt ) 〉 and the absolute wave angle of attack 〈 | δ a ( gdt ) | 〉 along the shortest-distance route. Firstly, it should be noted that an increase in wave height can lead to either substantial or minimal CO 2 emission savings. This outcome depends on whether the prevailing wave direction opposes or aligns with the vessel's heading. When focusing on routes with a CO 2 saving of at least 2 %, it is seen that they mostly refer to either beam or head seas along the least-distance route. This corresponds to elevated speed loss and subsequent higher emissions, as reported in Fig.  6 b and d. This subset of routes shows a trend of larger savings in rougher sea states. Conversely, when encountering following seas with even higher H s , savings remain below 1 %. This is due to both a smaller speed reduction and a lower CO 2 emission rate. The counts of routes surpassing the 2 % saving threshold accounts for more than 1 / 10 of the total routes, the ones above the 10 % threshold, represent about 1 / 38 th of the cases. This implies that, for the given ferry and the specified route, double-digit percentage savings can be anticipated for about 10 calendar days per year.

The analysis of the CO 2 savings distribution can be conducted by also considering the role of the engine load factor χ , as depicted in Fig.  12 b. The distribution curves exhibit a bi-exponential shape, with the larger of the two decay lengths ( d 2 ) inversely proportional to the magnitude of χ ; cf. Table  10 . This relationship is connected to the observation of reduced speed loss at higher χ as rougher sea conditions are experienced, which was already noted in the characteristics of this vessel in Sect.  2.5.1 . The distribution's tail can extend to values ranging between 20 % and 50 %, depending on the specific value of χ .

Table 9 Average relative savings of the CO 2 -optimal vs. the least-distance route (in %), for various engine loads ( χ ), considering just waves (wa) or also currents (wa-cu), for ferry routes between Toulon (FRTLN) and Porto Torres (ITPTO) as in Fig.  11 . The χ -averaged values are also provided in the “Avg” columns.

and assignment operator in python

Percentage CO 2 savings, broken down by sailing direction and considering the presence or absence of currents, are detailed in Table  9 . The average savings range from 0.6 % (1.0 % when considering sea currents) to 1.9 % (2.2 %). It is confirmed that the savings are more substantial on the route that navigates against the mistral wind (from Porto Torres to Toulon). However, the percentage savings are amplified when currents are taken into account, and this effect is particularly noticeable for the routes sailing in the downwind direction.

https://gmd.copernicus.org/articles/17/4355/2024/gmd-17-4355-2024-f12

Figure 12 Metrics relative to ferry routes pooled on sailing directions (FRTLN  ↔  ITPTO) and χ , using both waves and currents. (a)  Percentage savings, with the markers' grey shade representing the mean angle of attack along the least-distance route. The total number of routes, including those with relative CO 2 savings above 2 % (solid line) and 10 % (dashed), are also provided; (b)  Distributions of the CO 2 savings for each χ value, with fitted bi-exponential functions as in Table  10 . Each set of four columns pertains to a bin centred on the nearest tick mark and spanning a width of 5 %.

Table 10 Fit coefficients of y = a ⋅ [ exp ( - x / d 1 ) + b ⋅ exp ( - x / d 2 ) ] on the data of Fig.  12 b.

and assignment operator in python

Further comments regarding the comparison of the CO 2 savings presented here with the existing literature can be found in Sect.  6 . While other works also hint at the presence of optimal route bundles, VISIR-2 marks the first comprehensive exploration of how CO 2 savings are distributed across various environmental conditions and engine loads.

5.2.2  Sailboat

The chosen area lies in the southern Aegean Sea, along a route connecting Greece (Monemvasia) and Türkiye (Marmaris). This area spans one of the most archipelagic zones in the Mediterranean Sea, holding historical significance as the birthplace of the term “archipelago”. The sea conditions in this area are influenced by the meltemi, prevailing northerly winds, particularly during the summer season. Such an “Etesian” weather pattern can extend its influence across a substantial portion of the Levantine basin ( Lionello et al. ,  2008 ; Schroeder and Chiggiato ,  2022 ) . On the eastern side of the domain, the circulation is characterised by the westbound Asia Minor Current, while on its western flank, two prominent cyclonic structures separated by the west Cretan anticyclonic gyre are usually found ( Theocharis et al. ,  1999 ) .

We performed numerical experiments with VISIR-2, with a graph resolution of ( ν , 1 / Δ x ) = ( 5 , 15 / ° ) , leading to 2874 nodes and 156 162 edges in the selected domain. The resolution of the time grid was Δ τ =30   min . Furthermore, N τ =120 time steps of the environmental fields and k =2 iterations for Eq. ( A1 ) were used. A First 36.7 sailboat was selected. For each day, both route orientations and all possible combinations of wind, current, and leeway were considered. This gave a total of 2920 numerical experiments. Each route required a total computing time of about 7  min , of which the edge weight and shortest-path computation amounted to 4  min , mainly spent on the edge weight computation. The excess time in comparison to the motor vessel's case study is attributed to both a higher value of N τ and the additional time required for accounting for the exclusion of the no-go zone of the sailboat shown in Fig.  7 .

In Fig.  13 a, a sailboat route is depicted for a specific departure date, superimposed on the wind and sea current patterns. Both the least-distance and least-time routes appropriately steer clear of continental or insular landmasses, with the time-optimal route opting for a more extensive detour. This adjustment is aimed at harnessing more favourable winds and circumventing unfavourable or cross currents, culminating in a remarkable 14.6 % reduction in route duration.

Moving to Fig.  13 b, the collective set or “bundle” of eastbound routes is presented. Unlike the ferry routes showcased in Fig.  11 b, it proves more challenging to discern a distinct seasonal pattern for the diversions of the sailboat routes. A metric for measuring diversions, such as the Fréchet distance utilised in Mannarini et al. ( 2019 a ) , could facilitate the identification of patterns. The corresponding return routes are shown in Sect. S4.2 of the Supplement, confirming this trend. The bundles indicate that also accounting for currents leads to a more expansive set of optimal routes.

In only five cases (constituting 1.7 × 10 - 3 of all sailboat routes), the least-time route was discovered to be slower than the least-distance route. These instances are scrutinised in Sect. S3.2 of the Supplement. The apparent inconsistency arises from the fact that these least-time routes arrive at certain intermediate waypoints earlier but encounter less favourable sailing conditions compared to those encountered by the least-distance routes arriving later. This discrepancy points to a non-FIFO situation (refer to Sect.  2.4.1 ). This scenario necessitates advancements in the least-time algorithm to accommodate dynamic edge weights, potentially incorporating an initial waiting time, as discussed in Orda and Rom ( 1990 ) .

https://gmd.copernicus.org/articles/17/4355/2024/gmd-17-4355-2024-f13

Figure 13 The sailboat's optimal routes between GRMON and TRMRM, considering both wind and currents: (a)  for the specified departure date and time, the least-time route is depicted in red, and the shortest-distance one is in blue. The wind field is represented in shades of grey with black arrows, while the currents are shown in purple tones with white streamlines. Additionally, isochrones of the time-optimal route are displayed at 6-hourly intervals. (b)  A bundle of all eastbound time-optimal routes is presented, with the line colour indicating the departure month.

A statistical evaluation of the time savings resulting from the optimisation process for sailboat routes is illustrated in Fig.  14 a. Thereby, Eq. ( 23 ) is employed to assess both the path length and duration percentage savings. The −d T savings are generally proportional to path lengthening d L , particularly under nearly upwind conditions along the least-distance route, i.e. where 〈 | δ i ( gdt ) | 〉 ∼ α 0 (cf. Eq.  7 ). This is understandable, as reduced sustained speeds and extended edge sailing times occur when wind originates from sectors close to the no-go zone, as depicted in Fig.  7 a.

It is important to acknowledge that, under excessively weak or consistently sustained upwind conditions, a sailboat route might become unfeasible. A quantitative overview of such “failed” routes is provided in Table  11 . It is evident that, thanks to the spatial diversions introduced by the route optimisation process, the likelihood of a least-time route failing, compared to the least-distance one, is reduced by a factor of approximately 100. In the “Video supplement” accompanying this paper, all sailboat routes between Monemvasia and Marmaris in 2022, along with the corresponding environmental fields, are included.

In Fig.  14 b, the impact of currents and leeway is assessed. The influence of currents leads to a change in duration of up to approximately 5 % when compared to routes affected solely by the wind. Categorising the data based on sailing direction (as presented in Sect. S5 in the Supplement), currents primarily contribute to shorter route durations for westbound courses (benefiting from the Asia Minor Current). Conversely, they primarily result in extended durations for eastbound routes, particularly where, to the north of the island of Rhodes, there is no alternative but to sail against the current.

Turning to leeway, when not in combination with currents, it consistently extends the duration of routes, particularly, as indicated in the Supplement, when facing upwind conditions (more likely for westbound routes), as the speed loss is exacerbated due to a higher leeway speed (region with δ i ∼ α 0 in Fig.  7 b).

As in our earlier comment in Sect.  2.1 , the impact of leeway is mainly provided by its cross-course component, which invariably decreases the vessel's SOG. Notably, the longitudinal component is smaller than the cross one by a tan  δ factor; cf. Eq. ( 17 ). With δ estimated from Eq. ( 14 ) and Fig.  7 b to fall within a range of a few degrees, the along-edge projection of leeway, w ∥ ( L ) , measures approximately 1 / 10 of the transversal one, w ⊥ ( L ) .

When both effects, currents and leeway, are considered together, the distribution of duration changes in comparison to wind-only routes resembles the distribution for the case with currents only. However, due to the impact of leeway, it is slightly skewed towards longer durations.

Finally in Table  11 time savings averaged throughout the year are presented. These savings are further categorised based on the direction of sailing and the specific combination of effects, including wind, currents, and leeway. The impact of sea currents generally increases the percentage duration savings from 2.4 % (the directional average of the wind-only or wind and leeway cases) to 3.2 % (the average across all results affected by sea currents). We observe that routes featuring prevailing upwind conditions and favourable westbound currents, while also accounting for leeway, typically yield greater percentage duration savings compared to corresponding eastbound routes. This outcome can be attributed to the increase in duration of the least-distance route, which results from the loss of sailboat manoeuvrability as the no-go zone is approached. It is also noted that the number of failed routes increases in the presence of leeway during upwind sailing. More statistical metrics are provided in Table S9 of the Supplement. Finally we observe that, in VISIR-2, rigging is regarded as fixed (cf. Table  3 ), whereas in actual sailing practice, it may be optimised based on both the wind intensity and the point of sail.

https://gmd.copernicus.org/articles/17/4355/2024/gmd-17-4355-2024-f14

Figure 14 Metrics of the sailboat's optimal routes pooled on sailing directions (GRMON  ↔  TRMRM). (a)  Duration percentage savings −d T vs. relative lengthening d L considering just wind: the markers' grey shade represents the average angle of attack of wind | 〈 δ i ( gdt ) 〉 | along the least-distance route. The number of data (#data) is given by ∑ d 365 - N f ( g ) , where d represents the two sailing directions and the N f ( g ) values are from the first row in Table  11 . (b)  Histograms of relative route duration T f , with environmental forcing combination f defined by the column colour, with respect to the duration T wi of the wind-only optimal routes.

Table 11 Average time savings of the sailboat routes (in %), considering just wind (wi) or also various combinations of currents (cu) and leeway (le) for the sailboat routes between Monemvasia (GRMON) and Marmaris (TRMRM) as in Fig.  13 . The number of failed routes for the least-distance N f ( g ) or the least-time routes N f ( o ) is also provided.

and assignment operator in python

In this section, we critically compare the CO 2 savings achieved in Sect.  2.5.1 for the ferry's optimal routes with those reported in the ship weather routing literature (Sect.  6.1 ). Furthermore, we explore potential applications and users of VISIR-2 (Sect.  6.2 ) and provide some insights into possible developments (Sect.  6.3 ).

6.1  Comparing CO 2 savings with the literature

Only a handful of peer-reviewed papers have reported results on emission savings through ship routing, yet a few of these findings are reviewed here for comparison with VISIR-2's results.

For the ferry case study examined in this paper, the CO 2 emissions can be halved compared to those along the least-distance route in the best case (Fig.  12 ). This is in numerical agreement with the broad (0.1–48) % range reported in Bouman et al. ( 2017 , Table 2) . Notably, the upper limit reduction stands as an outlier, with the more probable values depicted in Bouman et al. ( 2017 , Fig. 2) falling below 10 %. This aligns well with the results obtained from the statistical distribution of VISIR-2 experiments, presented in both Fig.  12 b and Table  9 of this paper.

Applying the VOIDS model, Mason et al. ( 2023 a , Sect. 3.2) discovered that, for eastbound routes of a Panamax bulk carrier in the North Atlantic, voyage optimisation contributed to carbon savings ranging from 2.2 % to 13.2 %. This is a narrower range compared to the present findings of VISIR-2 (cf. Fig.  12 ). However, both a different vessel type (a ferry) and a different domain of sailing (the western Mediterranean Sea) were considered in our numerical experiments.

Miola et al. ( 2011 ) presented data from the second IMO GHG study, where the estimated CO 2 abatement potential for weather routing on the emissions of 2020 was reported to be as low as 0.24 %. In the same paper, a DNV study on projected emissions in 2030 was also cited, providing an estimate of 3.9 % for the CO 2 abatement potential through weather routing. The former figure compares well to the average emission reduction computed via VISIR-2 for the ferry downwind conditions and high engine load and the latter to results for upwind and low engine load (cf. Table  9 ).

Lindstad et al. ( 2013 ) estimated the reduction in CO 2 emissions for a dry bulk Panamax vessel navigating in head seas during a typical stormy period in the North Atlantic. This reduction was determined when sailing on a 4500 nmi (nautical miles; 8300 km) route compared to the shorter (yet stormier) least-distance route of 3600  nmi (6700 km). They found reductions ranging from 11 % to 48 %, depending on the speed of the vessel.

We note that, as for example in Mason et al. ( 2023 a , Fig. 7) , VISIR-2 optimal routes also exhibit spatial variations contingent on the departure date, forming a bundle as illustrated in Fig.  11 b and Sect. S4 of the Supplement. The shape of route boundaries was assessed for the United States’ Atlantic coast routes by means of AIS data in Breithaupt et al. ( 2017 ) . However, while multimodal distributions depending on sailing direction were noted, the authors did not attribute the preferential lanes to the presence of ocean currents but speculated that it was due to bathymetric constraints or artificial aids to navigation.

VISIR possesses a capability to incorporate ocean currents into the voyage optimisation process. As shown in Mannarini and Carelli ( 2019 b ) , this integration has proven to significantly reduce the duration of transatlantic routes. In the present paper, we reaffirm the positive impact of currents on ship route optimisation, also extending their benefits to the reduction in CO 2 emissions (Table  9 ) and to the determination of more faithful duration savings for sailboat routes (Table  11 ).

In general, both average and extreme CO 2 emission percentage savings found in the literature align well with the results obtained in the ferry case study presented in our paper. Nevertheless, engaging in a meaningful discussion of numerical differences, given the diverse range of vessel types, routes, environmental fields, and computational methods employed in the various published case studies, proves challenging.

VISIR-2 contributes to the existing body of literature by providing an open computational platform that facilitates the simulation of optimal ship routes in the presence of waves, currents, and wind. These simulations are designed to be transparent, with customisable sea domain and vessel performance curves, allowing for thorough inspection, modification, and evaluation. This addresses the concern raised by Zis et al. ( 2020 ) regarding the necessity of benchmarking instances of optimal routes and the associated input data. By providing such benchmarks, VISIR-2 supports and streamlines the work of future researchers in the field. Hence, we believe that the critical task of evaluating inter-model differences will best be addressed through dedicated inter-comparison studies, as previously demonstrated with VISIR-1 ( Mannarini et al. ,  2019 b ) .

6.2  Potential uses of VISIR-2

Given its open-source nature, validated results, and numerical stability, VISIR-2 can have great utility across various fields. The fact that both motor vessels and sailboats are treated equally will make VISIR-2 suitable for use in weather routing of vessels with wind-assisted propulsion.

Moreover, VISIR-2 can serve as a valuable tool for regulatory bodies seeking to make informed policies on shipping. As previously outlined, agencies like the European Maritime Safety Agency (EMSA), which oversee systems for monitoring, reporting, and verifying emissions, could utilise the model – provided that vessel performance curves and GHG emission rates are available – to calculate baseline emissions for various vessel and GHG types. With the inclusion of shipping in the EU-ETS, shipowners, ship managers, or bareboat charterers – whoever bears the fuel cost – are mandated to surrender allowances for their emissions. These stakeholders may find it beneficial to explore open-source solutions alongside existing commercial options.

VISIR-2 also has the potential to help reduce uncertainty regarding the effectiveness of weather routing in reducing CO 2 emissions ( Bullock et al. ,  2020 ) . For instance, evaluating distributions as in Fig.  12 b, it becomes possible to characterise the joint potential of sea domains and vessel types for GHG emission savings. This concept also aligns with the idea of a “green corridor of shipping”, as envisioned by both the Clydebank Declaration ( gov.uk ,  2021 ) and the United States Department of State ( DoS ,  2022 ) . In these initiatives, VISIR-2, thanks to the generality of its optimisation algorithm (Algorithms  1 , 2 ), could play a crucial role in minimising the consumption of costly zero-carbon fuel.

Furthermore, VISIR-2 could be used to generate a dataset of optimal routes for the training of artificial intelligence systems for autonomous vessels ( Li and Yang ,  2023 ) , surpassing the shortcomings of using AIS tracks, which include incomplete coverage ( Filipiak et al. ,  2020 ) . Finally, we note that, as open-source software, VISIR-2 can even have educational purposes, providing training opportunities for ship officials and maritime surveillance authorities, as well as for beginner sailors.

6.3  Outlook

There are several possible avenues for future developments of VISIR-2: the computer science, the algorithms, the ocean engineering, and the environmental fields.

First, as mentioned in Sect.  4 , some computational performance improvements for the least-distance procedure should be feasible. In applications where large domains, hyper-resolution, or multiple-input environmental fields are required, it will be necessary to devise a solution that effectively reduces the computer's memory allocation. To further enhance modularity of VISIR-2, future developments can focus on object-oriented programming principles. Containerisation of VISIR-2 is currently underway as part of the development of a digital twin of the ocean ( https://www.edito-modellab.eu/ , last access: 20 May 2024).

Further algorithmic work could address, for instance, construction of the graph directly in the projection space, facilitating the presence of more isotropic ship courses and perfectly collinear edges (cf. Sect.  2.2.2 ); development of an algorithm for given-duration, least-CO 2 routes; incorporation of multi-objective optimisation techniques ( Szlapczynska ,  2015 ; Sidoti et al. ,  2017 ) ; generalisation of the least-time algorithm to non-FIFO situations (cf. Sect.  2.4.1 ); and consideration of tacking time and motor assistance for sailboats or WAPSs.

Transitioning to upgrades in ocean engineering for VISIR-2, the focus could shift towards targeting large ocean-going vessels, contingent upon the availability of related performance curves. Safety constraints on vessel intact stability ( IMO ,  2018 b ) ; considerations of slamming, green water, and lateral acceleration ( Vettor and Guedes Soares ,  2016 ) ; passenger comfort as highlighted by Carchen et al. ( 2021 ) ; or vessel performance in the presence of cross seas could be integrated. Second-generation intact stability criteria ( Begovic et al. ,  2023 ) could be accounted for through a dynamic masking of the graph. VISIR-2's readiness for wind-assisted ship propulsion hinges on the availability of an appropriate vessel performance curve that accounts for the added resistance from both wind and waves.

In terms of environmental data, it should be feasible to extend beyond the reliance on surface currents alone by incorporating the initial few depth layers of ocean models. Furthermore, VISIR-2 currently operates under the assumption of having perfect knowledge of meteo-oceanographic conditions, which is provided through forecast fields for shorter voyages or analysis fields for longer ones. The latter corresponds to retracked routes as discussed in Mason et al. ( 2023 b ) . However, for real-time applications during extended voyages, it is essential to incorporate adaptive routing strategies. This entails using the latest forecasts to execute re-routing as needed.

This paper presented the development of VISIR-2: a modular, validated, and portable Python-coded model for ship weather routing. It provides a consistent framework for both motor vessels and sailboats by accounting for dynamic environmental fields such as waves, currents, and wind. The model can compute optimal ship routes even in complex and archipelagic domains. A cartographic projection, a feature that had been overlooked up to now, has been introduced in VISIR-2. The model provides, for vessels with an angle-dependent performance curve, an improved level of accuracy in the velocity composition with sea currents. It is found that heading and course differ by an angle of attack, which is given by the solution of a transcendental equation (Eq.  13 ) involving an effective flow being the vector sum of currents and leeway. A computationally inexpensive iterative solution has been devised (Appendix  A ). Furthermore, a variant of Dijkstra's algorithm is introduced and used, which can minimise not just the CO 2 emissions but any figure of merit depending on dynamic edge weights (cf. Algorithms  1 , 2 ).

The validation of VISIR-2 included comparisons to oracles and two inter-comparison exercises. Differently from the few available ship weather routing packages or services, the VISIR-2 software is accompanied by comprehensive documentation, making it suitable for community use.

The computational performance of the VISIR-2 shortest-path module displayed a significant enhancement compared to its predecessor, VISIR-1 (Sect.  4 ). A quasi-linear scaling with problem complexity was demonstrated for up to 1×10 9  DOFs. The robustness of VISIR-2 was demonstrated across thousands of flawless route computations.

While the model is general with respect to vessel type, two case studies with VISIR-2, based on realistic vessel seakeeping models, were documented in this paper.

From nearly 6000 routes of a 125 m long ferry, computed considering both waves and currents in the northwestern Mediterranean, average CO 2 savings between 0.6 % and 2.2 %, depending on the engine load and prevailing sailing direction, were found. The distribution of the savings was bi-exponential, with the longer decay length becoming more pronounced at lower engine loads. This implied in particular that two-digit percentage CO 2 savings, up to 49 %, were possible for about 10 d annually. This statistical distribution sheds new light on the underlying factors contributing to the variability observed in the role of weather routing, as reported in previous review studies ( Bouman et al. ,  2017 ; Bullock et al. ,  2020 ) . Furthermore, our findings bear significance for both the environmental impact of greenhouse gas emissions and the financial considerations within the EU-ETS.

From close to 3000 routes of an 11 m sailboat, within the southern Aegean Sea, accounting for both wind and currents, an average sailing time reduction of 2.4 % was observed. When considering currents as a factor, the duration of optimal routes could further be reduced by 3.2 %. Additionally, confirming prior work by Sidoti et al. ( 2023 ) , disregarding the role of leeway would lead to an incorrect estimation of the route duration in upwind conditions. Several cases of non-FIFO behaviour were detected, and there is potential for addressing them in the future through the refinement of the current least-time algorithm. All of these discoveries hold the potential to influence not just sailboat racing but also the utilisation of wind to aid in the propulsion of motor vessels.

In summary, this paper provides comprehensive documentation of the scientific hypotheses and decisions underpinning the development of an open-source ship routing model while also contributing to the quantification of achievable reductions in greenhouse gas emissions through voyage optimisation.

The angle δ between the ship's heading and course is obtained from the transcendental equation, Eq. ( 13 ). Its solution can be approximated by the following iteration:

where k is the number of iterations of the function

with γ being a constant resulting from the use of Eq. ( 2 ). The k =1 case corresponds to the solution provided in Mannarini and Carelli ( 2019 b ) .

https://gmd.copernicus.org/articles/17/4355/2024/gmd-17-4355-2024-f15

Figure A1 Approximate vs. exact solution of Eq. ( 13 ) for a First 36.7 sailboat. (a)  Iterative solution of Eq. ( A1 ) with k =1 vs. the exact solution, using ω ⊥ as the marker colour; (b)  unexplained variance ( R is the Pearson's correlation coefficient) of the linear regression and fitted slope coefficient for various k  values.

Both Eqs. ( 13 ) and ( A1 ) were evaluated for a sailboat as in Sect.  2.5.2 using environmental conditions (wind, currents) for a domain in the central Adriatic Sea. A total of 11 hourly time steps and 18 474 edges from a graph with ( ν , 1 / Δ x ) = ( 4 , 12 / ° ) were considered, resulting in a total of about 2×10 5 edge weight values. The iterative solution from Eq. ( A1 ) was compared to the roots of Eq. ( 13 ) found via the scipy.optimize.root solver, using as an initial guess the δ (1) solution of Eq. ( A1 ) (see the velocity_eval.py function in the VISIR-2 code). In what follows, the numerical solution from the solver is termed “exact”. The benefit of the approximated solution Eq. ( A1 ) is that it can easily be parallelised on all graph arcs, while this is not possible for the exact solution, which processes one arc at a time.

The outcome for a sailboat is provided in Fig.  A1 a. It is seen that the iterative approximation departs from the exact solution for δ angles larger than about 5°. Such departures are mainly related to the effective cross flow ω ⊥ (marker colour, determining the elongation from the origin). However, it is just a tiny fraction of the edges that present such departures, so the R 2 correlation coefficient between the exact solution and its approximation is almost identical to 1 for any k >0 , as shown in Fig.  A1 b.

The case k =0 corresponds to neglecting the loss of ships' momentum to balance the effective cross flow of Eq. ( 11b ). Therefore, it wrongly underestimates the sailing times. For the First 36.7 sailboat under consideration here, the k =1 solution leads to a slope about 5 % off. Already for k =2 the correct slope is achieved within an error of 2 ‰. For the ferry, the k =1 iteration is sufficient to reach a 2 % accuracy; see Sect. S6.1 in the Supplement. This could be due to the ferry having a smoother angular dependence than the sailboat's one, as seen from Figs.  6 b and 7 a. Finally, in Fig. S22 of the Supplement, evidence of the validation of the exact solution in the absence of currents, Eq. ( 14 ), is also provided.

For identifying the vessel performance curves from a LUT via a neural network, a multi-layer perceptron was used.

The models were built and trained via the scikit-learn package ( https://scikit-learn.org/stable/ , last access: 20 May 2024). A 3-fold cross-validation was used to identify the best model for each vessel performance function. Different solvers, hidden layers' sizes, L2 regularisation terms, and activation functions were explored, covering a search space of about 10 3 models. The optimal configuration made use of the rectified linear unit activation function, the Adam optimiser to minimise mean-squared error, for at most 10 3 passes through the training set (“epochs”) with a batch size of 200, a constant learning rate of 10 −4 , and early stopping after the validation loss fails to decrease for 10 epochs.

The source code of VISIR-2 is available from Salinas et al. ( 2024 a ) ( https://doi.org/10.5281/zenodo.10960842 ). The distribution includes a user manual. Raw data in the form of input datasets and graphs used for the route computations are available from Salinas et al. ( 2024 b ) ( https://doi.org/10.5281/zenodo.10674079 ). Intermediate data products in the form of routes for producing figures and tables in Sect.  5 are available from Salinas et al. ( 2024 c ) ( https://doi.org/10.5281/zenodo.10674082 ).

Videos for this paper are available at https://doi.org/10.5446/s_1687 (ferry case study, Salinas ,  2024 a ) and https://doi.org/10.5446/s_1688 (sailboat, Salinas ,  2024 b ).

The supplement related to this article is available online at:  https://doi.org/10.5194/gmd-17-4355-2024-supplement .

GM: conceptualisation, funding acquisition, methodology, project administration, supervision, validation, writing (original draft), writing (review and editing); MLS: data curation, investigation, software, validation, visualisation; LC: data curation, investigation, software, validation, visualisation; NP: investigation, resources; JO: investigation, resources.

The contact author has declared that none of the authors has any competing interests.

The authors are not liable for casualties or losses that may occur in using routes computed via VISIR-2 for navigation purposes. Publisher's note: Copernicus Publications remains neutral with regard to jurisdictional claims made in the text, published maps, institutional affiliations, or any other geographical representation in this paper. While Copernicus Publications makes every effort to include appropriate place names, the final responsibility lies with the authors.

Both ChatGPT-3 and Gemini were utilised to review sections of this paper for English-language accuracy.

This research has been supported by Interreg (grant nos. 10043587 and 10253074) and Horizon Europe (grant nos. 101093293 and 101138583).

This paper was edited by David Ham and reviewed by two anonymous referees.

Al-Aboosi, F. Y., El-Halwagi, M. M., Moore, M., and Nielsen, R. B.: Renewable ammonia as an alternative fuel for the shipping industry, Current Opinion in Chemical Engineering, 31, 100670, https://doi.org/10.1016/j.coche.2021.100670 , 2021.  a

Begovic, E., Bertorello, C., Rinauro, B., and Rosano, G.: Simplified operational guidance for second generation intact stability criteria, Ocean Eng., 270, 113583, https://doi.org/10.1016/j.oceaneng.2022.113583 , 2023.  a

Bentley, J. L.: Multidimensional binary search trees used for associative searching, Communications of the ACM, 18, 509–517, 1975.  a

Bertsekas, D.: Network Optimization: Continuous and Discrete Models, Athena Scientific, Belmont, Mass. 02178-9998, USA, 1998.  a , b , c , d , e

Bouman, E. A., Lindstad, E., Rialland, A. I., and Strømman, A. H.: State-of-the-art technologies, measures, and potential for reducing GHG emissions from shipping – A review, Transport. Res. D-Tr. E., 52, 408–421, https://doi.org/10.1016/j.trd.2017.03.022 , 2017.  a , b , c , d

Breithaupt, S. A., Copping, A., Tagestad, J., and Whiting, J.: Maritime Route Delineation using AIS Data from the Atlantic Coast of the US, J. Navigation, 70, 379–394, https://doi.org/10.1017/S0373463316000606 , 2017.  a

Breivik, Ø. and Allen, A. A.: An operational search and rescue model for the Norwegian Sea and the North Sea, J. Marine Syst., 69, 99–113, 2008.  a

Bullock, S., Mason, J., Broderick, J., and Larkin, A.: Shipping and the Paris climate agreement: a focus on committed emissions, BMC Energy, 2, 5, https://doi.org/10.1186/s42500-020-00015-2 , 2020.  a , b , c

Carchen, A., Gaggero, T., Besio, G., Mazzino, A., and Villa, D.: A method for the probabilistic assessment of the on-board comfort on a passenger vessel route, Ocean Eng., 225, 108702, https://doi.org/10.1016/j.oceaneng.2021.108 , 2021.  a

Claughton, A.: Developments in the IMS VPP Formulations, in: Fourteenth Chesapeake sailing yacht symposium, Annapolis, Maryland, 1–20, 1999.  a

Claughton, A. R.: Developments in hydrodynamic force models for velocity prediction programs, in: Proceedings of the International Conference The Modern Yacht, The Royal Institution of Naval Architects, RINA, Paper: P2003-4 Proceedings, ISBN 0 903055 91 0, 2003.  a

Dijkstra, E. W.: A note on two problems in connexion with graphs, Numerische Mathematik, 1.1, 269–271, https://doi.org/10.1145/3544585.3544600 , 1959.  a

DoS: Green Shipping Corridors Framework, Tech. rep., US Department of State, https://www.state.gov/green-shipping-corridors-framework/ (last access: 20 May 2024), 2022.  a

Faber, J., van Seters, D., and Scholten, P.: Shipping GHG emissions 2030: Analysis of the maximum technical abatement potential, Tech. rep., CE Delft, 2023.  a

Farkas, A., Parunov, J., and Katalinić, M.: Wave statistics for the middle Adriatic Sea, Pomorski zbornik, 52, 33–47, https://doi.org/10.18048/2016.52.02 , 2016.  a

Feeman, T. G.: Portraits of the Earth: A mathematician looks at maps, American Mathematical Soc., 18, 62–64, ISBN 0-8218-3255-7, 2002.  a

Filipiak, D., Węcel, K., Stróżyna, M., Michalak, M., and Abramowicz, W.: Extracting Maritime Traffic Networks from AIS Data Using Evolutionary Algorithm, Bus. Inf. Syst. Eng., 62, 435–450, https://doi.org/10.1007/s12599-020-00661-0 , 2020.  a

gov.uk: Clydebank Declaration, Tech. rep., UK Department for Transport, https://www.gov.uk/government/publications/cop-26-clydebank-declaration-for-green-shipping-corridors (last access: 20 May 2024), 2021.  a

Guedes Soares, C.: Effect of heavy weather maneuvering on the wave-induced vertical bending moments in ship structures, J. Ship Res., 34, 60–68, 1990.  a

IMO: MEPC.304(72) Initial IMO strategy on reduction of GHG emissions from ships, Tech. Rep. Annex 11, International Maritime Organization, London, UK, 2018a.  a

IMO: SDC 5/J/7 Finalization of second generation intact stability criteria, Tech. rep., International Maritime Organization, London, UK, 2018b.  a

IMO: MEPC.80/(WP.12) Report of the Working Group on Reduction of GHG Emissions from Ships Report of the Working Group on Reduction of GHG Emissions from Ships, Tech. rep., International Maritime Organization, London, UK, 2023.  a

IPCC: Sixth Assessment Report, WG3, Ch.10, Tech. rep., IPCC, https://www.ipcc.ch/report/ar6/wg3/ (last access: 20 May 2024), 2022.  a

IPCC: AR6 Synthesis Report: Climate Change 2023, Tech. rep., IPCC, https://www.ipcc.ch/report/ar6/syr/ (last access: 20 May 2024), 2023.  a

Ladany, S. P. and Levi, O.: Search for optimal sailing policy, European J. Oper. Res., 260, 222–231, https://doi.org/10.1016/j.ejor.2016.12.013 , 2017.  a

Laxague, N. J., Özgökmen, T. M., Haus, B. K., Novelli, G., Shcherbina, A., Sutherland, P., Guigand, C. M., Lund, B., Mehta, S., Alday, M., and Molemaker, J.: Observations of near-surface current shear help describe oceanic oil and plastic transport, Geophys. Res. Lett., 45, 245–249, 2018.  a

Le Goff, C., Boussidi, B., Mironov, A., Guichoux, Y., Zhen, Y., Tandeo, P., Gueguen, S., and Chapron, B.: Monitoring the greater Agulhas Current with AIS data information, J. Geophys. Res.-Oceans, 126, e2021JC017228, https://doi.org/10.1029/2021JC017228 , 2021.  a

Li, H. and Yang, Z.: Incorporation of AIS data-based machine learning into unsupervised route planning for maritime autonomous surface ships, Transport. Res. E-Log., 176, 103171, https://doi.org/10.1016/j.tre.2023.103171 , 2023.  a

Lindstad, H., Asbjørnslett, B. E., and Jullumstrø, E.: Assessment of profit, cost and emissions by varying speed as a function of sea conditions and freight market, Transport. Res. D-Tr. E., 19, 5–12, https://doi.org/10.1016/j.trd.2012.11.001 , 2013.  a

Lionello, P., Cogo, S., Galati, M., and Sanna, A.: The Mediterranean surface wave climate inferred from future scenario simulations, Global Planet. Change, 63, 152–162, https://doi.org/10.1016/j.gloplacha.2008.03.004 , 2008.  a

Lolla, S. V. T.: Path planning and adaptive sampling in the coastal ocean, Ph.D. thesis, Massachusetts Institute of Technology, http://hdl.handle.net/1721.1/103438 (last access: 20 May 2024), 2016.  a

Maneewongvatana, S. and Mount, D. M.: It's okay to be skinny, if your friends are fat, in: Center for geometric computing 4th annual workshop on computational geometry, 2, 1–8, 1999.  a

Mannarini, G. and Carelli, L.: [VISIR-1.b ship routing model] source code (Matlab), Zenodo [code], https://doi.org/10.5281/zenodo.2563074 , 2019a.  a

Mannarini, G. and Carelli, L.: VISIR-1.b: ocean surface gravity waves and currents for energy-efficient navigation, Geosci. Model Dev., 12, 3449–3480, https://doi.org/10.5194/gmd-12-3449-2019 , 2019b.  a , b , c , d , e , f , g , h , i , j , k , l , m , n , o

Mannarini, G., Lecci, R., and Coppini, G.: Introducing sailboats into ship routing system VISIR, in: 2015 6th International Conference on Information, Intelligence, Systems and Applications (IISA), IEEE, 1–6, https://doi.org/10.1109/IISA.2015.7387962 , 2015.  a

Mannarini, G., Pinardi, N., Coppini, G., Oddo, P., and Iafrati, A.: VISIR-I: small vessels – least-time nautical routes using wave forecasts, Geosci. Model Dev., 9, 1597–1625, https://doi.org/10.5194/gmd-9-1597-2016 , 2016a.  a , b , c , d , e , f , g

Mannarini, G., Turrisi, G., D'Anca, A., Scalas, M., Pinardi, N., Coppini, G., Palermo, F., Carluccio, I., Scuro, M., Cretì, S., Lecci, R., Nassisi, P., and Tedesco, L.: VISIR: technological infrastructure of an operational service for safe and efficient navigation in the Mediterranean Sea, Nat. Hazards Earth Syst. Sci., 16, 1791–1806, https://doi.org/10.5194/nhess-16-1791-2016 , 2016b.  a

Mannarini, G., Carelli, L., Zissis, D., Spiliopoulos, G., and Chatzikokolakis, K.: Preliminary inter-comparison of AIS data and optimal ship tracks, TransNav, 13, 53–61, https://doi.org/10.12716/1001.13.01.04 , 2019a.  a

Mannarini, G., Subramani, D., Lermusiaux, P., and Pinardi, N.: Graph-Search and Differential Equations for Time-Optimal Vessel Route Planning in Dynamic Ocean Waves, IEEE T. Intell. Transp., 21, 3581–3593, https://doi.org/10.1109/TITS.2019.2935614 , 2019b.  a , b , c , d , e , f

Mannarini, G., Carelli, L., Orović, J., Martinkus, C. P., and Coppini, G.: Towards Least-CO 2 Ferry Routes in the Adriatic Sea, J. Marine Sci. Eng., 9, 115, https://doi.org/10.3390/jmse9020115 , 2021.  a

Mason, J., Larkin, A., Bullock, S., van der Kolk, N., and Broderick, J. F.: Quantifying voyage optimisation with wind propulsion for short-term CO 2 mitigation in shipping, Ocean Eng., 289, 116065, https://doi.org/10.1016/j.oceaneng.2023.116065 , 2023a.  a , b

Mason, J., Larkin, A., and Gallego-Schmid, A.: Mitigating stochastic uncertainty from weather routing for ships with wind propulsion, Ocean Eng., 281, 114674, https://doi.org/10.1016/j.oceaneng.2023.114674 , 2023b.  a , b , c , d

Miola, A., Marra, M., and Ciuffo, B.: Designing a climate change policy for the international maritime transport sector: Market-based measures and technological options for global and regional policy actions, Energy Policy, 39, 5490–5498, https://doi.org/10.1016/j.enpol.2011.05.013 , 2011.  a

Orda, A. and Rom, R.: Shortest-path and Minimum-delay Algorithms in Networks with Time-dependent Edge-length, J. ACM, 37, 607–625, https://doi.org/10.1145/79147.214078 , 1990.  a , b , c

Salinas, M.: Ferry case study, TIB AVPortal [video], https://doi.org/10.5446/s_1687 , 2024a.  a

Salinas, M.: Sailboat case study, TIB AVPortal [video], https://doi.org/10.5446/s_1688 , 2024b.  a

Salinas, M. L., Carelli, L., and Mannarini, G.: [VISIR-2 ship weather routing model] source code (Python), Zenodo [code], https://doi.org/10.5281/zenodo.10960842 , 2024a.  a , b , c , d , e

Salinas, M. L., Carelli, L., and Mannarini, G.: [VISIR-2 ship weather routing model] raw data, Zenodo [data set], https://doi.org/10.5281/zenodo.10674079 , 2024b.  a

Salinas, M. L., Carelli, L., and Mannarini, G.: [VISIR-2 ship weather routing model] intermediate products, Zenodo [data set], https://doi.org/10.5281/zenodo.10674082 , 2024c.  a

Schroeder, K. and Chiggiato, J.: Oceanography of the Mediterranean Sea: An Introductory Guide, Elsevier, ISBN 978-0-12-823692-5, 2022.  a , b

Sidoti, D., Avvari, G. V., Mishra, M., Zhang, L., Nadella, B. K., Peak, J. E., Hansen, J. A., and Pattipati, K. R.: A Multiobjective Path-Planning Algorithm With Time Windows for Asset Routing in a Dynamic Weather-Impacted Environment, IEEE T. Syst. Man Cyb., 47, 3256–3271, https://doi.org/10.1109/TSMC.2016.2573271 , 2017.  a

Sidoti, D., Pattipati, K. R., and Bar-Shalom, Y.: Minimum Time Sailing Boat Path Algorithm, IEEE J. Ocean. Eng., 48, 307–322, https://doi.org/10.1109/JOE.2022.3227985 , 2023.  a , b

Smith, T. and Shaw, A.: An overview of the discussions from IMO MEPC 80 and Frequently Asked Questions, Tech. rep., UMAS, 2023.  a

Svanberg, M., Ellis, J., Lundgren, J., and Landälv, I.: Renewable methanol as a fuel for the shipping industry, Renew. Sustain. Energ. Rev., 94, 1217–1228, https://doi.org/10.1016/j.rser.2018.06.058 , 2018.  a

Szlapczynska, J.: Multi-objective weather routing with customised criteria and constraints, J. Navigation, 68, 338–354, https://doi.org/10.1017/S0373463314000691 , 2015.  a

Tagliaferri, F., Philpott, A., Viola, I., and Flay, R.: On risk attitude and optimal yacht racing tactics, Ocean Eng., 90, 149–154, https://doi.org/10.1016/j.oceaneng.2014.07.020 , 2014.  a

Theocharis, A., Balopoulos, E., Kioroglou, S., Kontoyiannis, H., and Iona, A.: A synthesis of the circulation and hydrography of the South Aegean Sea and the Straits of the Cretan Arc (March 1994–January 1995), Prog. Oceanogr., 44, 469–509, https://doi.org/10.1016/S0079-6611(99)00041-5 , 1999.  a

van den Bremer, T. S. and Breivik, Ø.: Stokes drift, Philos. T. Roy. Soc. A, 376, 20170104, https://doi.org/10.1098/rsta.2017.0104 , 2018.  a

Vettor, R. and Guedes Soares, C.: Development of a ship weather routing system, Ocean Eng., 123, 1–14, https://doi.org/10.1016/j.oceaneng.2016.06.035 , 2016.  a , b

Wilson, G., Aruliah, D., Brown, C. T., Hong, N. P. C., Davis, M., Guy, R. T., Haddock, S. H., Huff, K. D., Mitchell, I. M., Plumbley, M. D., Waugh, B., White, E. P., and Wilson, P: Best practices for scientific computing, PLoS Biol., 12, e1001745, https://doi.org/10.1371/journal.pbio.1001745 , 2014.  a , b

Zis, T. P., Psaraftis, H. N., and Ding, L.: Ship weather routing: A taxonomy and survey, Ocean Eng., 213, 107697, https://doi.org/10.1016/j.oceaneng.2020.107697 , 2020.  a , b , c

  • Introduction
  • Technical advancements
  • Computational performance
  • Case studies
  • Conclusions
  • Appendix A:  Angle of attack
  • Appendix B:  Neural network features
  • Code and data availability
  • Video supplement
  • Author contributions
  • Competing interests
  • Acknowledgements
  • Financial support
  • Review statement

Ship weather routing has the potential to reduce CO 2 emissions, but it currently lacks open and...

IMAGES

  1. Python 3 Tutorial

    and assignment operator in python

  2. Assignment operators in python

    and assignment operator in python

  3. Python Tutorials: Assignment Operators In python

    and assignment operator in python

  4. 7 Types of Python Operators that will ease your programming

    and assignment operator in python

  5. PPT

    and assignment operator in python

  6. 7 Types of Python Operators that will ease your programming

    and assignment operator in python

VIDEO

  1. Assignment

  2. Assignment Operators in python #python #operator

  3. Python Assignment Operator #coding #assignmentoperators #phython

  4. Assignment Operator in Python Lec 7

  5. python assignment operator

  6. Python datatypes operator

COMMENTS

  1. Python's Assignment Operator: Write Robust Assignments

    To create a new variable or to update the value of an existing one in Python, you'll use an assignment statement. This statement has the following three components: A left operand, which must be a variable. The assignment operator ( =) A right operand, which can be a concrete value, an object, or an expression.

  2. Assignment Operators in Python

    The Walrus Operator in Python is a new assignment operator which is introduced in Python version 3.8 and higher. This operator is used to assign a value to a variable within an expression. Syntax: a := expression. Example: In this code, we have a Python list of integers. We have used Python Walrus assignment operator within the Python while loop.

  3. Python Assignment Operators

    Python Assignment Operators. Assignment operators are used to assign values to variables: Operator. Example. Same As. Try it. =. x = 5. x = 5.

  4. Using the "and" Boolean Operator in Python

    Python's and operator takes two operands, which can be Boolean expressions, objects, or a combination. With those operands, the and operator builds more elaborate expressions. The operands in an and expression are commonly known as conditions. If both conditions are true, then the and expression returns a true result.

  5. Python Assignment Operators

    Assignment operators in Python. The above code is useful when we want to update the same number. We can also use two different numbers and use the assignment operators to apply them on two different values. num_one = 6. num_two = 3. print(num_one) num_one += num_two. print(num_one) num_one -= num_two.

  6. Operators and Expressions in Python

    The assignment operator is one of the most frequently used operators in Python. The operator consists of a single equal sign ( = ), and it operates on two operands. The left-hand operand is typically a variable , while the right-hand operand is an expression.

  7. Python Operators: Arithmetic, Assignment, Comparison, Logical, Identity

    Python Operators: Arithmetic, Assignment, Comparison, Logical, Identity, Membership, Bitwise. Operators are special symbols that perform some operation on operands and returns the result. For example, 5 + 6 is an expression where + is an operator that performs arithmetic add operation on numeric left operand 5 and the right side operand 6 and ...

  8. Variables and Assignment

    Variables and Assignment¶. When programming, it is useful to be able to store information in variables. A variable is a string of characters and numbers associated with a piece of information. The assignment operator, denoted by the "=" symbol, is the operator that is used to assign values to variables in Python.The line x=1 takes the known value, 1, and assigns that value to the variable ...

  9. PEP 572

    This shows that what looks like an assignment operator in an f-string is not always an assignment operator. The f-string parser uses : to indicate formatting options. To preserve backwards compatibility, assignment operator usage inside of f-strings must be parenthesized. As noted above, this usage of the assignment operator is not recommended.

  10. Different Assignment operators in Python

    Simple assignment operator in Python. The Simple assignment operator in Python is denoted by = and is used to assign values from the right side of the operator to the value on the left side.. Input: a = b + c Add and equal operator. This operator adds the value on the right side to the value on the left side and stores the result in the operand on the left side.

  11. Augmented Assignment Operators in Python

    An assignment operator is an operator that is used to assign some value to a variable. Like normally in Python, we write "a = 5" to assign value 5 to variable 'a'. Augmented assignment operators have a special role to play in Python programming.

  12. Assignment Operator in Python

    The simple assignment operator is the most commonly used operator in Python. It is used to assign a value to a variable. The syntax for the simple assignment operator is: variable = value. Here, the value on the right-hand side of the equals sign is assigned to the variable on the left-hand side. For example.

  13. Python Operators (With Examples)

    Assignment operators are used to assign values to variables. For example, # assign 5 to x x = 5. Here, = is an assignment operator that assigns 5 to x. Here's a list of different assignment operators available in Python.

  14. Python

    Python Assignment Operator. The = (equal to) symbol is defined as assignment operator in Python. The value of Python expression on its right is assigned to a single variable on its left. The = symbol as in programming in general (and Python in particular) should not be confused with its usage in Mathematics, where it states that the expressions ...

  15. python

    1. In python and other languages like C, "=" is a assignment operator and is used to assign a value to a variable. Example: a=2 # the value of a is 2. whereas "==" is Comparison operator and is used to check whether 2 expressions give the same value .Equality check returns true if it succeeds and else return false. Example: a=2 b=3 c=2.

  16. Python Operators

    Python Operators. Operators are used to perform operations on variables and values. In the example below, we use the + operator to add together two values: Example. print(10 + 5) ... Assignment operators are used to assign values to variables: Operator Example Same As Try it = x = 5: x = 5:

  17. The Walrus Operator: Python 3.8 Assignment Expressions

    Each new version of Python adds new features to the language. For Python 3.8, the biggest change is the addition of assignment expressions.Specifically, the := operator gives you a new syntax for assigning variables in the middle of expressions. This operator is colloquially known as the walrus operator.. This tutorial is an in-depth introduction to the walrus operator.

  18. Assignment Operators in Programming

    Assignment operators are used in programming to assign values to variables. We use an assignment operator to store and update data within a program. They enable programmers to store data in variables and manipulate that data. The most common assignment operator is the equals sign (=), which assigns the value on the right side of the operator to ...

  19. Python Operators

    Python has seven types of operators that we can use to perform different operation and produce a result. Arithmetic operator. Relational operators. Assignment operators. Logical operators. Membership operators. Identity operators. Bitwise operators.

  20. What does colon equal (:=) in Python mean?

    The code in the question is pseudo-code; there, := represents assignment. For future visitors, though, the following might be more relevant: the next version of Python (3.8) will gain a new operator, :=, allowing assignment expressions (details, motivating examples, and discussion can be found in PEP 572, which was provisionally accepted in late June 2018).

  21. coding style

    In simpler form, this is also commonly used to designate a default... In fact, they produce concise one-line expressions that help to eliminate line noise from the code. This behavior is the basis for a form of the if/else ternary operator: A = Y if X else Z. edited Jan 5, 2012 at 19:40. answered Jan 5, 2012 at 19:12. joaquin. 84.4k 31 142 154.

  22. Assignment Expressions: The Walrus Operator

    In this lesson, you'll learn about the biggest change in Python 3.8: the introduction of assignment expressions.Assignment expression are written with a new notation (:=).This operator is often called the walrus operator as it resembles the eyes and tusks of a walrus on its side.. Assignment expressions allow you to assign and return a value in the same expression.

  23. and Decrement -= Assignment Operators in Python

    An assignment operator is an operator that is used to assign some value to a variable. Like normally in Python, we write "a = 5" to assign value 5 to variable 'a'. Augmented assignment operators have a special role to play in Python programming. It basically combines the functioning of the arithmetic or bitwise operator with the assignment operator

  24. Welcome to Python.org

    The core of extensible programming is defining functions. Python allows mandatory and optional arguments, keyword arguments, and even arbitrary argument lists. More about defining functions in Python 3. Python is a programming language that lets you work quickly and integrate systems more effectively. Learn More.

  25. operators (and similar)

    Are the operations "atomic" or is a += 1 split into: read a. add 1 to a. replace a with the result. with the possibility that another thread could also write to a in the space between 2 and 3. (I'm assuming that the one thing that is guaranteed is that the reference counting is fine, whatever else happens). c-rob (Chuck R.) May 25, 2024 ...

  26. Conditional Statements in Python

    Remember, if-statements are meant to help direct the flow of a program.Let's say I make a simple program to help determine what grade a student should receive based on a test score. In my first draft of code, I use multiple if-statements, but it doesn't return the desired results. The output returned every possible grade assignment that would be true.

  27. Operator Precedence and Associativity in C++

    In C++, operator precedence specifies the order in which operations are performed within an expression. When an expression contains multiple operators, those with higher precedence are evaluated before those with lower precedence. For expression: int x = 5 - 17 * 6; As, multiplication has higher precedence than subtraction, that's why 17 * 6 ...

  28. GMD

    Abstract. Ship weather routing, which involves suggesting low-emission routes, holds potential for contributing to the decarbonisation of maritime transport. However, including because of a lack of readily deployable open-source and open-language computational models, its quantitative impact has been explored only to a limited extent. As a response, the graph-search VISIR (discoVerIng Safe and ...