LipidSpecies.java
/*
* Copyright 2021 Dominik Kopczynski, Nils Hoffmann.
*
* 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.lifstools.jgoslin.domain;
import com.fasterxml.jackson.annotation.JsonIgnore;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
/**
* A lipid species is the factual root of the object hierarchy. Lipid category
* and class are used as taxonomic roots of a lipid species. Partial structural
* knowledge, apart from the head group, is first encoded in the lipid species.
*
* A typical lipid species is PC 32:0 (SwissLipids SLM:000056493), where the
* head group is defined as PC (Glycerophosphocholines), with fatty acyl chains
* of unknown individual composition, but known total composition (32 carbon
* atoms, zero double bonds, no hydroxylations or other functions).
*
* @author Dominik Kopczynski
* @author Nils Hoffmann
*/
public class LipidSpecies {
protected Headgroup headGroup;
protected LipidSpeciesInfo info;
protected HashMap<String, FattyAcid> fa = new HashMap<>();
protected ArrayList<FattyAcid> faList = new ArrayList<>();
public LipidSpecies(Headgroup _headgroup, KnownFunctionalGroups knownFunctionalGroups) {
this(_headgroup, Collections.emptyList(), knownFunctionalGroups);
}
public LipidSpecies(Headgroup _headGroup, Collection<FattyAcid> _fa, KnownFunctionalGroups knownFunctionalGroups) {
headGroup = _headGroup;
info = new LipidSpeciesInfo(headGroup.getLipidClass(), knownFunctionalGroups);
info.setLevel(LipidLevel.SPECIES);
// add fatty acids
if (_fa != null && !_fa.isEmpty()) {
int i = 0;
FattyAcid fattyAcid = _fa.iterator().next();
boolean fa_it = (_fa.size() > 0) && (fattyAcid.lipidFaBondType == LipidFaBondType.LCB_EXCEPTION || fattyAcid.lipidFaBondType == LipidFaBondType.LCB_REGULAR);
for (FattyAcid fatty_acid : _fa) {
fatty_acid.name = (fa_it && i == 0) ? "LCB" : "FA" + String.valueOf(i + 1 - (fa_it ? 1 : 0));
fatty_acid.position = -1;
info.add(fatty_acid);
++i;
}
}
}
public LipidLevel getLipidLevel() {
return LipidLevel.SPECIES;
}
public LipidSpeciesInfo getInfo() {
return info;
}
public Headgroup getHeadGroup() {
return headGroup;
}
/**
* Returns the normalized lipid string on the native level.
*
* @return the normalized lipid string.
*/
public String getLipidString() {
return getLipidString(LipidLevel.NO_LEVEL);
}
/**
* Returns the normalized lipid string on the provided level.
*
* @param level the lipid level at which the lipid string should be
* generated.
* @return the normalized lipid string.
* @throws IllegalArgumentException when the provided level is not
* supported.
*/
public String getLipidString(LipidLevel level) {
switch (level) {
case UNDEFINED_LEVEL ->
throw new IllegalArgumentException("LipidSpecies does not know how to create a lipid string for level " + level.toString());
case CLASS, CATEGORY -> {
return headGroup.getLipidString(level);
}
case NO_LEVEL, SPECIES -> {
StringBuilder lipid_string = new StringBuilder();
lipid_string.append(headGroup.getLipidString(level));
if (info.getElements().get(Element.C) > 0 || info.numCarbon > 0) {
LipidSpeciesInfo lsi = info.copy();
for (HeadgroupDecorator decorator : headGroup.getDecorators()) {
if (decorator.getName().equals("decorator_alkyl") || decorator.getName().equals("decorator_acyl")) {
ElementTable e = decorator.computeAndCopyElements();
lsi.numCarbon += e.get(Element.C);
lsi.doubleBonds.setNumDoubleBonds(lsi.doubleBonds.getNumDoubleBonds() + decorator.getNDoubleBonds());
}
}
lipid_string.append(headGroup.getLipidCategory() != LipidCategory.ST ? " " : "/").append(lsi.toString());
}
return lipid_string.toString();
}
default ->
throw new IllegalArgumentException("LipidSpecies does not know how to create a lipid string for level " + level.toString());
}
}
public String getExtendedClass() {
boolean special_case = (info.numCarbon > 0) ? (headGroup.getLipidCategory() == LipidCategory.GP) : false;
String class_name = headGroup.getClassName();
if (special_case && (info.extendedClass == LipidFaBondType.ETHER_PLASMANYL || info.extendedClass == LipidFaBondType.ETHER_UNSPECIFIED)) {
return class_name + "-O";
} else if (special_case && info.extendedClass == LipidFaBondType.ETHER_PLASMENYL) {
return class_name + "-P";
}
return class_name;
}
public ArrayList<FattyAcid> getFaList() {
return faList;
}
@JsonIgnore
public ElementTable getElements() {
switch (info.getLevel()) {
case COMPLETE_STRUCTURE, FULL_STRUCTURE, STRUCTURE_DEFINED, SN_POSITION, MOLECULAR_SPECIES, SPECIES -> {
}
default ->
throw new LipidException("Element table cannot be computed for lipid level " + info.getLevel().toString());
}
if (headGroup.isUseHeadgroup()) {
throw new LipidException("Element table cannot be computed for lipid level " + info.getLevel().toString());
}
ElementTable elements = headGroup.getElements();
elements.add(info.getElements());
// since only one FA info is provided, we have to treat this single information as
// if we would have the complete information about all possible FAs in that lipid
LipidClassMeta meta = LipidClasses.getInstance().get(headGroup.getLipidClass());
int additional_fa = meta.possibleNumFa;
int remaining_H = meta.maxNumFa - additional_fa;
int hydrochain = meta.specialCases.contains("HC") ? 1 : 0;
elements.put(Element.O, elements.get(Element.O) - (-additional_fa + info.numEthers + (headGroup.isSpException() ? 1 : 0) + hydrochain));
elements.put(Element.H, elements.get(Element.H) + (-additional_fa + remaining_H + 2 * info.numEthers + 2 * hydrochain));
if (meta.specialCases.contains("Amide")) {
elements.put(Element.O, elements.get(Element.O) - meta.maxNumFa);
elements.put(Element.H, elements.get(Element.H) + meta.maxNumFa);
}
return elements;
}
}