/* * Copyright 2014 Global Biodiversity Information Facility (GBIF) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.gbif.api.vocabulary; import java.util.List; import java.util.Map; import java.util.Set; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; /** * An ordered taxonomic rank enumeration with the most frequently used values. * Several static methods, lists, sets and maps are provided to help with ordering and lookup from strings. * * @see <a href="http://rs.gbif.org/vocabulary/gbif/rank.xml">rs.gbif.org vocabulary</a> */ public enum Rank { DOMAIN("dom."), SUPERKINGDOM("superreg."), KINGDOM("reg."), SUBKINGDOM("subreg."), INFRAKINGDOM("infrareg."), SUPERPHYLUM("superphyl."), PHYLUM("phyl."), SUBPHYLUM("subphyl."), INFRAPHYLUM("infraphyl."), SUPERCLASS("supercl."), CLASS("cl."), SUBCLASS("subcl."), INFRACLASS("infracl."), PARVCLASS("parvcl."), SUPERLEGION("superleg."), /** * Sometimes used in zoology, e.g. for birds and mammals */ LEGION("leg."), SUBLEGION("subleg."), INFRALEGION("infraleg."), SUPERCOHORT("supercohort"), /** * Sometimes used in zoology, e.g. for birds and mammals */ COHORT("cohort"), SUBCOHORT("subcohort"), INFRACOHORT("infracohort"), MAGNORDER("magnord."), SUPERORDER("superord."), GRANDORDER("grandord."), ORDER("ord."), SUBORDER("subord."), INFRAORDER("infraord."), PARVORDER("parvord."), SUPERFAMILY("superfam."), FAMILY("fam."), SUBFAMILY("subfam."), INFRAFAMILY("infrafam."), SUPERTRIBE("supertrib."), TRIBE("trib."), SUBTRIBE("subtrib."), INFRATRIBE("infratrib."), /** * Used for any other unspecific rank above genera. */ SUPRAGENERIC_NAME("supragen."), GENUS("gen."), SUBGENUS("subgen."), INFRAGENUS("infragen."), SECTION("sect."), SUBSECTION("subsect."), SERIES("ser."), SUBSERIES("subser."), /** * used for any other unspecific rank below genera and above species. */ INFRAGENERIC_NAME("infrageneric"), /** * A loosely defined group of species. * Zoology: Aggregate - a group of species, other than a subgenus, within a genus. An aggregate may be denoted by a group name interpolated in parentheses. * The Berlin/MoreTax model notes: [these] aren't taxonomic ranks but cirumscriptions because on the one hand they are necessary for the concatenation * of the fullname and on the other hand they are necessary for distinguishing the aggregate or species group from the microspecies. */ SPECIES_AGGREGATE("agg."), SPECIES("sp."), /** * used for any other unspecific rank below species. */ INFRASPECIFIC_NAME("infrasp."), /** * The term grex has been coined to expand botanical nomenclature to describe hybrids of orchids. * Grex names are one of the three categories of plant names governed by the International Code of Nomenclature for Cultivated Plants * Within a grex the Groups category can be used to refer to plants by their shared characteristics (rather than by their parentage), * and individual orchid plants can be selected (and propagated) and named as cultivars * https://en.wikipedia.org/wiki/Grex_(horticulture) */ GREX("grex"), SUBSPECIES("subsp."), /** * Rank in use from the code for cultivated plants. * It does not use a classic rank marker but indicated the Group rank after the actual groups name * For example Rhododendron boothii Mishmiense Group * or Primula Border Auricula Group * * Sometimes authors also used the words "sort", "type", "selections" or "hybrids" instead of Group which is not legal according to the code. */ CULTIVAR_GROUP, /** * A group of cultivars. These can be roughly comparable to cultivar groups, but convarieties, unlike cultivar groups, * do not necessarily contain named varieties, and convarieties are members of traditional "Linnaean" ranks. * The ICNCP replaced this term with the term cultivar-group, and convarieties should not be used in modern cultivated plant taxonomy. * * From Spooner et al., Horticultural Reviews 28 (2003): 1-60 */ CONVARIETY("convar."), /** * used also for any other unspecific rank below subspecies. */ INFRASUBSPECIFIC_NAME("infrasubsp."), /** * Botanical legacy rank */ PROLES("prol."), /** * Botanical legacy rank */ RACE("race"), /** * Zoological legacy rank */ NATIO("natio"), /** * Zoological legacy rank */ ABERRATION("ab."), /** * Zoological legacy rank */ MORPH("morph"), VARIETY("var."), SUBVARIETY("subvar."), FORM("f."), SUBFORM("subf."), /** * Microbial rank based on pathogenic reactions in one or more hosts. * For recommendations on designating pathovars and use of designations when reviving names see * Dye et al. (1980) Standards for naming pathovars of phytopathogenic bacteria and a list of pathovar names and pathotype strains. * Rev. Plant Pathol. 59:153–168. * See <a href="http://www.ncbi.nlm.nih.gov/books/NBK8812/table/A844/?report=objectonly">Bacteriological Code</a> * See <a href="http://www.isppweb.org/about_tppb_naming.asp">International Standards for Naming Pathovars of Phytopathogenic Bacteria</a> * See <a href="http://sipav.org/main/jpp/index.php/jpp/article/view/682">Demystifying the nomenclature of bacterial plant pathogens</a> * See <a href="http://link.springer.com/chapter/10.1007/978-94-009-3555-6_171">Problems with the Pathovar Concept</a> * For example Pseudomonas syringae pv. lachrymans */ PATHOVAR("pv."), /** * Microbial rank based on biochemical or physiological properties. * See <a href="http://www.ncbi.nlm.nih.gov/books/NBK8812/table/A844/?report=objectonly">Bacteriological Code</a> * For example Francisella tularensis biovar tularensis */ BIOVAR("biovar"), /** * Microbial rank based on production or amount of production of a particular chemical. * See <a href="http://www.ncbi.nlm.nih.gov/books/NBK8812/table/A844/?report=objectonly">Bacteriological Code</a> * For example Vibrio alginolyticus chemovar iophagus */ CHEMOVAR("chemovar"), /** * Microbial rank based on morphological characterislics. * See <a href="http://www.ncbi.nlm.nih.gov/books/NBK8812/table/A844/?report=objectonly">Bacteriological Code</a> * For example Acinetobacter junii morphovar I */ MORPHOVAR("morphovar"), /** * Microbial infrasubspecific rank based on reactions to bacteriophage. * See <a href="http://www.ncbi.nlm.nih.gov/books/NBK8812/table/A844/?report=objectonly">Bacteriological Code</a> * For example Staphyloccocus aureus phagovar 42D */ PHAGOVAR("phagovar"), /** * Microbial infrasubspecific rank based on antigenic characteristics. * See <a href="http://www.ncbi.nlm.nih.gov/books/NBK8812/table/A844/?report=objectonly">Bacteriological Code</a> * For example Salmonella enterica serovar Dublin */ SEROVAR("serovar"), /** * Microbial infrasubspecific rank based on chemical constitution. * See <a href="http://www.ncbi.nlm.nih.gov/books/NBK8812/table/A844/?report=objectonly">Bacteriological Code</a> * For example Thymus vulgaris ct. geraniol */ CHEMOFORM("chemoform"), /** * Microbial infrasubspecific rank. * A parasitic, symbiotic, or commensal microorganism distinguished primarily by adaptation to a particular host or habitat. * Named preferably by the scientific name of the host in the genitive. * See <a href="http://www.ncbi.nlm.nih.gov/books/NBK8812/table/A844/?report=objectonly">Bacteriological Code</a> * For example Puccinia graminis f. sp. avenae */ FORMA_SPECIALIS("f.sp."), CULTIVAR("cv."), /** * A microbial strain. */ STRAIN("strain"), /** * Any other rank we cannot map to this enumeration */ OTHER, UNRANKED; /** * All main Linnean ranks ordered. */ public static final List<Rank> LINNEAN_RANKS = ImmutableList.of( KINGDOM, PHYLUM, CLASS, ORDER, FAMILY, GENUS, SPECIES ); /** * An ordered list of all ranks that appear in Darwin Core with their own term. */ public static final List<Rank> DWC_RANKS = ImmutableList.of( KINGDOM, PHYLUM, CLASS, ORDER, FAMILY, GENUS, SUBGENUS, SPECIES ); /** * A set of ranks which cannot clearly be compared to any other rank as they represent rank "ranges". * For example a subgeneric rank is anything below genus, * so one cannot say if its higher or lower than a species for example. */ private static final Set<Rank> UNCOMPARABLE_RANKS = ImmutableSet.of( INFRAGENERIC_NAME, INFRASPECIFIC_NAME, INFRASUBSPECIFIC_NAME, OTHER, UNRANKED ); private static final Set<Rank> LEGACY_RANKS = ImmutableSet.of( MORPH, ABERRATION, NATIO, RACE, PROLES, CONVARIETY ); private static final Map<Rank, NomenclaturalCode> RANK2CODE= ImmutableMap.<Rank, NomenclaturalCode>builder() .put(PARVCLASS, NomenclaturalCode.ZOOLOGICAL) .put(MAGNORDER, NomenclaturalCode.ZOOLOGICAL) .put(GRANDORDER, NomenclaturalCode.ZOOLOGICAL) .put(PARVORDER, NomenclaturalCode.ZOOLOGICAL) .put(SUPERLEGION, NomenclaturalCode.ZOOLOGICAL) .put(LEGION, NomenclaturalCode.ZOOLOGICAL) .put(SUBLEGION, NomenclaturalCode.ZOOLOGICAL) .put(INFRALEGION, NomenclaturalCode.ZOOLOGICAL) .put(SUPERCOHORT, NomenclaturalCode.ZOOLOGICAL) .put(COHORT, NomenclaturalCode.ZOOLOGICAL) .put(SUBCOHORT, NomenclaturalCode.ZOOLOGICAL) .put(INFRACOHORT, NomenclaturalCode.ZOOLOGICAL) .put(MORPH, NomenclaturalCode.ZOOLOGICAL) .put(ABERRATION, NomenclaturalCode.ZOOLOGICAL) .put(NATIO, NomenclaturalCode.ZOOLOGICAL) .put(RACE, NomenclaturalCode.BOTANICAL) .put(PROLES, NomenclaturalCode.BOTANICAL) .put(SECTION, NomenclaturalCode.BOTANICAL) .put(SUBSECTION, NomenclaturalCode.BOTANICAL) .put(SERIES, NomenclaturalCode.BOTANICAL) .put(SUBSERIES, NomenclaturalCode.BOTANICAL) .put(CULTIVAR, NomenclaturalCode.CULTIVARS) .put(CULTIVAR_GROUP, NomenclaturalCode.CULTIVARS) .put(CONVARIETY, NomenclaturalCode.CULTIVARS) .put(GREX, NomenclaturalCode.CULTIVARS) .put(PATHOVAR, NomenclaturalCode.BACTERIAL) .put(BIOVAR, NomenclaturalCode.BACTERIAL) .put(CHEMOVAR, NomenclaturalCode.BACTERIAL) .put(MORPHOVAR, NomenclaturalCode.BACTERIAL) .put(PHAGOVAR, NomenclaturalCode.BACTERIAL) .put(SEROVAR, NomenclaturalCode.BACTERIAL) .put(CHEMOFORM, NomenclaturalCode.BACTERIAL) .put(FORMA_SPECIALIS, NomenclaturalCode.BACTERIAL) .build(); private final String marker; Rank() { this(null); } Rank(String marker) { this.marker = marker; } public String getMarker() { return marker; } /** * @return true for infraspecific ranks. */ public boolean isInfraspecific() { return this != SPECIES && isSpeciesOrBelow(); } /** * @return true for infra subspecific ranks. */ public boolean isInfrasubspecific() { return ordinal() > SUBSPECIES.ordinal() && notOtherOrUnknown(); } /** * @return true for rank is below genus. Also incluse species and infraspecific ranks */ public boolean isInfrageneric() { return ordinal() > GENUS.ordinal() && notOtherOrUnknown(); } /** * True for all mayor Linnéan ranks, ie kingdom,phylum,class,order,family,genus and species. */ public boolean isLinnean() { for (Rank r : LINNEAN_RANKS) { if (r == this) { return true; } } return false; } public boolean isSpeciesOrBelow() { return ordinal() >= SPECIES.ordinal() && notOtherOrUnknown(); } public boolean notOtherOrUnknown() { return this != OTHER && this != UNRANKED; } /** * @return true if the rank is above genus. */ public boolean isSuprageneric() { return ordinal() < GENUS.ordinal(); } /** * @return true if the rank is above rank species. */ public boolean isSupraspecific() { return ordinal() < SPECIES.ordinal(); } /** * True for names of informal ranks that represent a range of ranks really and therefore cannot safely be compared to * other ranks in all cases. * Example ranks are INFRASPECIFIC_NAME or INFRAGENERIC_NAME * * @return true if uncomparable */ public boolean isUncomparable() { return UNCOMPARABLE_RANKS.contains(this); } /** * @return true if the rank is considered a legacy rank not used anymore in current nomenclature. */ public boolean isLegacy() { return LEGACY_RANKS.contains(this); } /** * @return the nomenclatural code if the rank is restricted to just one code or null otherwise */ public NomenclaturalCode isRestrictedToCode() { return RANK2CODE.get(this); } /** * @return true if this rank is higher than the given other */ public boolean higherThan(Rank other) { return ordinal() < other.ordinal(); } }