Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • metexplore/met4j
1 result
Show changes
Commits on Source (2)
Showing
with 1067 additions and 1 deletion
package fr.inrae.toulouse.metexplore.met4j_core.biodata.multinetwork;
import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioCompartment;
import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioMetabolite;
import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioNetwork;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;
public class CommunityNetworkBuilder extends MetaNetworkBuilder implements MultiNetworkBuilder{
private BioCompartment medium;
public CommunityNetworkBuilder(){
setMedium();
}
public CommunityNetworkBuilder(BioCompartment medium){
this.medium=medium;
this.addNewSharedCompartment(medium);
}
public CommunityNetworkBuilder(Set<BioNetwork> networks){
setMedium();
Map<BioNetwork,String> prefixes = networks.stream()
.collect(Collectors.toMap(n->n,n->n.getId()+"_"));
this.setEntityFactory(new PrefixedMetaEntityFactory(prefixes,"pool"));
for(BioNetwork bn : networks){
this.add(bn);
}
}
private void setMedium(){
this.medium = new BioCompartment(UUID.randomUUID().toString(),"medium");
this.addNewSharedCompartment(medium);
}
public void exchangeWithMedium(BioNetwork sourceNetwork, BioCompartment sourceCompartment, BioMetabolite metabolite){
this.exchangeWithSharedCompartment(sourceNetwork, sourceCompartment, metabolite, medium);
};
public void add(BioNetwork bn, BioCompartment externalComp) {
super.add(bn);
this.fuseCompartmentIntoSharedCompartment(bn,externalComp,medium);
}
}
package fr.inrae.toulouse.metexplore.met4j_core.biodata.multinetwork;
import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioCompartment;
import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioMetabolite;
import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioNetwork;
public record MetaBioMetabolite(BioMetabolite metabolite, BioCompartment sourceCompartment, BioNetwork sourceNetwork) {
public MetaBioMetabolite(BioMetabolite metabolite, BioCompartment sourceCompartment, BioNetwork sourceNetwork){
if(!sourceNetwork.containsMetabolite(metabolite.getId())) throw new IllegalArgumentException("Source network does not contains metabolites");
if(!sourceNetwork.containsCompartment(sourceCompartment.getId())) throw new IllegalArgumentException("Source network does not contains source compartment");
if(sourceCompartment.getComponentsView().get(metabolite.getId())==null) throw new IllegalArgumentException("Source compartment does not contains metabolites");
this.metabolite = metabolite;
this.sourceCompartment = sourceCompartment;
this.sourceNetwork = sourceNetwork;
}
}
package fr.inrae.toulouse.metexplore.met4j_core.biodata.multinetwork;
import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioCompartment;
import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioEntity;
import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioMetabolite;
import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioNetwork;
import java.util.Collection;
/**
* Factory to create new instances of BioEntity and avoid id conflicts between subnetworks in a meta-graph.
**/
public interface MetaEntityFactory {
/**
* Create a copy of a subnetwork's BioEntity for its MetaGraph, while guaranteeing no id conflicts if the same
* original id was used in another subnetworks. This may be done by referencing in the new id the source network
* passed as parameter.
* @param originalEntity the original entity
* @param source the source network
**/
<E extends BioEntity> E createMetaEntity(E originalEntity, BioNetwork source);
/**
* Create a copy of a subnetwork's BioMetabolite in a shared compartment.
* @param originalEntity the original entity
* @param sharedComp the target shared compartment
* @return
*/
BioMetabolite createSharedCompound(BioMetabolite originalEntity, BioCompartment sharedComp);
/**
* Create a new BioMetabolite in a shared compartment, that represent a pool of compounds from different subnetworks.
* @param entities the matching entities in different subnetworks
* @param sharedComp the target shared compartment
* @return
*/
BioMetabolite createPoolCompound (Collection<BioMetabolite> entities, BioCompartment sharedComp);
}
package fr.inrae.toulouse.metexplore.met4j_core.biodata.multinetwork;
import fr.inrae.toulouse.metexplore.met4j_core.biodata.*;
import fr.inrae.toulouse.metexplore.met4j_core.biodata.collection.BioCollection;
import lombok.Getter;
import lombok.Setter;
import java.util.*;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
* A class that creates a meta-network from multiple sub-networks. A meta-network is a single model which contains several
* sub-networks that remain individualized within the meta-network (as opposed to models fusion), but which can share
* some of their components with other sub-networks through shared compartments.
*/
public class MetaNetworkBuilder implements MultiNetworkBuilder{
private Map<BioMetabolite,BioMetabolite> metaboliteConversion;
private Map<BioCompartment,BioCompartment> compartmentConversion;
private Map<BioReaction,BioReaction> reactionConversion;
private Map<BioProtein,BioProtein> proteinConversion;
private Map<BioEnzyme,BioEnzyme> enzymeConversion;
private Map<BioGene,BioGene> geneConversion;
protected BioCollection<BioNetwork> networks = new BioCollection<>();
private Map<BioCompartment, Set<MetaBioMetabolite>> metaCompComposition = new HashMap<>();
@Setter
protected Function<BioMetabolite,String> getSharedIdFunction = BioEntity::getName;
@Setter
private String poolReactionPrefix = "poolReaction_";
@Setter
private String sharedTransportPrefix = "transport_";
@Setter
private String exchangeReactionPrefix = "exchange_";
@Setter
protected BiFunction<BioMetabolite, BioMetabolite, BioReaction> createLinkWithSharedPool = (m, pool) -> {
BioReaction r=new BioReaction(poolReactionPrefix+ m.getId());
r.setReversible(true);
return r;
};
@Setter
protected Function<BioMetabolite, BioReaction> createPoolExchangeReaction = (pool) -> {
BioReaction r=new BioReaction(exchangeReactionPrefix+pool.getId());
r.setReversible(true);
return r;
};
@Setter
protected BiFunction<BioMetabolite, BioCompartment, BioReaction> createTransportWithSharedComp = (m, comp) -> {
BioReaction r=new BioReaction(sharedTransportPrefix+ m.getId()+"_to_"+comp.getId());
r.setReversible(true);
return r;
};
@Setter
@Getter
protected MetaEntityFactory entityFactory;
protected HashMap<BioCompartment,BioCompartment> fuseMap= new HashMap<>();
protected Boolean keepGPR = false;
@Setter
protected Boolean addExchangeReaction = true;
/**
* enable a compartment to be shared between multiple organisms
* @param sc a compartment that will be shared between multiple bionetworks
*/
public void addNewSharedCompartment(BioCompartment sc) {
metaCompComposition.put(sc,new HashSet<>());
}
/**
* Fuse a sub-network's compartment into a meta-network's shared compartment. The former will be replaced by the latter during build.
* All compartment's components will be added to the shared compartment
* @param n the sub-network
* @param c the sub-network's compartment to be fused
* @param sc the shared meta-compartment that will receive the compartment's components
*/
public void fuseCompartmentIntoSharedCompartment(BioNetwork n, BioCompartment c, BioCompartment sc) {
if(!metaCompComposition.containsKey(sc)) throw new IllegalArgumentException("Shared meta-compartment "+sc.getId()+" not found in network");
fuseMap.put(c,sc);
}
/**
* Bump a sub-network's compartment into a meta-network's shared compartment. For each compartment's component,
* a copy is created within the shared compartment
* @param n the sub-network
* @param c the sub-network's compartment to be bumped
* @param sc the shared meta-compartment that will receive the compartment's components
*/
public void bumpCompartmentIntoSharedCompartment(BioNetwork n, BioCompartment c, BioCompartment sc) {
BioCollection<BioMetabolite> toShare = n.getMetabolitesView().stream()
.filter(x -> n.getCompartmentsOf(x).contains(c))
.collect(BioCollection::new,BioCollection::add,BioCollection::addAll);
this.exchangeWithSharedCompartment(n,c,toShare,sc);
}
/**
* Exchange a compound from a sub-network's compartment to a meta-network's shared compartment. A copy of the compound will be created
* @param sourceNetwork the original subnetwork of the compound
* @param sourceCompartment the original compartment of the compound in the subnetwork
* @param metabolite the compound
* @param sc the target shared meta-compartment that will receive the compound
*/
public void exchangeWithSharedCompartment(BioNetwork sourceNetwork, BioCompartment sourceCompartment, BioMetabolite metabolite, BioCompartment sc) {
if(!metaCompComposition.containsKey(sc)) throw new IllegalArgumentException("Shared meta-compartment "+sc.getId()+" not found in network");
metaCompComposition.get(sc).add(new MetaBioMetabolite(metabolite,sourceCompartment,sourceNetwork));
}
/**
* Exchange compounds from a sub-network's compartment to a meta-network's shared compartment. A copy of each exchanged compound will be created
* @param sourceNetwork the original subnetwork of the compounds
* @param sourceCompartment the original compartment of the compounds in the subnetwork
* @param metabolites the compounds
* @param sc the target shared meta-compartment that will receive the compounds
*/
public void exchangeWithSharedCompartment(BioNetwork sourceNetwork, BioCompartment sourceCompartment, BioCollection<BioMetabolite> metabolites, BioCompartment sc) {
if(!metaCompComposition.containsKey(sc)) throw new IllegalArgumentException("Shared meta-compartment "+sc.getId()+" not found in network");
Set<MetaBioMetabolite> scCompo = metaCompComposition.get(sc);
for(BioMetabolite m : metabolites ){
scCompo.add(new MetaBioMetabolite(m,sourceCompartment,sourceNetwork));
}
}
@Override
public void add(BioNetwork bn) {
networks.add(bn);
}
/**
* creates all maps for conversion (original bioentity, new meta-entity)
* instantiate meta-network as new bionetwork
* @return an empty meta-network
*/
protected BioNetwork initMetaNetwork(){
this.metaboliteConversion = new HashMap<>();
this.compartmentConversion = new HashMap<>();
this.reactionConversion = new HashMap<>();
this.proteinConversion = new HashMap<>();
this.enzymeConversion = new HashMap<>();
this.geneConversion = new HashMap<>();
return new BioNetwork();
}
/**
* add all copied bioentity to the newly built meta-network
* @param meta the (usually empty) meta-network
*/
protected void populateMetaNetwork(BioNetwork meta){
for(BioNetwork sub : networks){
for(BioMetabolite e : sub.getMetabolitesView()){
BioMetabolite e2 = entityFactory.createMetaEntity(e,sub);
meta.add(e2);
metaboliteConversion.put(e,e2);
}
for(BioCompartment c : sub.getCompartmentsView()){
BioCompartment c2 = fuseMap.get(c);
if(c2==null){
c2 = entityFactory.createMetaEntity(c,sub);
meta.add(c2);
}
compartmentConversion.put(c,c2);
BioCollection<BioMetabolite> content = c.getComponentsView().stream()
.filter((e) -> e.getClass().equals(BioMetabolite.class))
.map(metaboliteConversion::get)
.collect(BioCollection::new,BioCollection::add,BioCollection::addAll);
meta.affectToCompartment(c2, content);
}
// Copy genes
if (keepGPR) {
//TODO case shared Genome
for (BioGene gene : sub.getGenesView()) {
BioGene newGene = entityFactory.createMetaEntity(gene,sub);
meta.add(newGene);
geneConversion.put(gene,newGene);
}
for (BioProtein protein : sub.getProteinsView()) {
BioProtein newProtein = entityFactory.createMetaEntity(protein,sub);
meta.add(newProtein);
proteinConversion.put(protein,newProtein);
if (protein.getGene() != null) {
BioGene newGene = geneConversion.get(protein.getGene());
meta.affectGeneProduct(newProtein, newGene);
}
}
for (BioEnzyme enzyme : sub.getEnzymesView()) {
BioEnzyme newEnzyme = entityFactory.createMetaEntity(enzyme,sub);
meta.add(newEnzyme);
enzymeConversion.put(enzyme,newEnzyme);
BioCollection<BioEnzymeParticipant> participants = enzyme.getParticipantsView();
for (BioEnzymeParticipant participant : participants) {
Double quantity = participant.getQuantity();
if (participant.getPhysicalEntity().getClass().equals(BioMetabolite.class)) {
BioMetabolite metabolite = (BioMetabolite) participant.getPhysicalEntity();
BioMetabolite newMetabolite = metaboliteConversion.get(metabolite);
meta.affectSubUnit(newEnzyme, quantity, newMetabolite);
} else if (participant.getPhysicalEntity().getClass().equals(BioProtein.class)) {
BioProtein protein = (BioProtein) participant.getPhysicalEntity();
BioProtein newProtein = proteinConversion.get(protein);
meta.affectSubUnit(newEnzyme, quantity, newProtein);
}
}
}
}
for (BioReaction r : sub.getReactionsView()) {
BioReaction newReaction = entityFactory.createMetaEntity(r,sub);
newReaction.setSpontaneous(r.isSpontaneous());
newReaction.setReversible(r.isReversible());
newReaction.setEcNumber(r.getEcNumber());
meta.add(newReaction);
reactionConversion.put(r,newReaction);
// Copy lefts
for (BioReactant reactant : r.getLeftReactantsView()) {
BioMetabolite newMetabolite = metaboliteConversion.get(reactant.getMetabolite());
BioCompartment newCpt = compartmentConversion.get(reactant.getLocation());
Double sto = reactant.getQuantity();
meta.affectLeft(newReaction, sto, newCpt, newMetabolite);
}
// Copy rights
for (BioReactant reactant : r.getRightReactantsView()) {
BioMetabolite newMetabolite = metaboliteConversion.get(reactant.getMetabolite());
BioCompartment newCpt = compartmentConversion.get(reactant.getLocation());
Double sto = reactant.getQuantity();
meta.affectRight(newReaction, sto, newCpt, newMetabolite);
}
// Copy enzymes
if (keepGPR) {
for (BioEnzyme enzyme : r.getEnzymesView()) {
BioEnzyme newEnzyme = enzymeConversion.get(enzyme);
meta.affectEnzyme(newReaction, newEnzyme);
}
}
}
for (BioPathway pathway : sub.getPathwaysView()) {
BioPathway newPathway = entityFactory.createMetaEntity(pathway,sub);
meta.add(newPathway);
// Add reactions into pathway
BioCollection<BioReaction> reactions = sub.getReactionsFromPathways(pathway);
for (BioReaction reaction : reactions) {
BioReaction newReaction = reactionConversion.get(reaction);
meta.affectToPathway(newPathway, newReaction);
}
}
}
}
/**
* Set the alias prefixes for the entities of the sub-networks. This allows to distinguish entities from different sub-networks
* that have the same name. The prefixes are added to the entity names in the meta-network.
* @param aliases a map of sub-networks and their respective prefixes
* (e.g. {subNetwork1: "prefix1", subNetwork2: "prefix2"})
* The prefixes are added to the entity names in the meta-network.
* If a sub-network is not in the map, or is in the map but has a null or empty prefix, its entities will not be prefixed.
**/
public void setAliasPrefixes(Map<BioNetwork,String> aliases, String poolPrefix){
this.setEntityFactory(new PrefixedMetaEntityFactory(aliases, poolPrefix));
}
@Override
public BioNetwork build() {
BioNetwork meta = this.initMetaNetwork();
//create shared compartment
this.initSharedComp(meta);
//add each subnetwork content
this.populateMetaNetwork(meta);
//add shared compartment components and exchanges
this.populateSharedComp(meta);
//link compounds in shared compartment
this.linkCompoundsInSharedComp(meta);
return meta;
}
protected void initSharedComp(BioNetwork meta) {
for (Map.Entry<BioCompartment, Set<MetaBioMetabolite>> compDescriptor : metaCompComposition.entrySet()) {
BioCompartment sc = compDescriptor.getKey();
meta.addCompartment(sc);
}
}
protected void populateSharedComp(BioNetwork meta){
for(Map.Entry<BioCompartment, Set<MetaBioMetabolite>> compDescriptor : metaCompComposition.entrySet()){
for(MetaBioMetabolite m : compDescriptor.getValue()){
BioMetabolite m1 = metaboliteConversion.get(m.metabolite());
BioMetabolite m2 = entityFactory.createSharedCompound(m1,compDescriptor.getKey());
meta.add(m2);
meta.affectToCompartment(compDescriptor.getKey(),m2);
BioReaction t = createTransportWithSharedComp.apply(m1,compDescriptor.getKey());
meta.add(t);
meta.affectLeft(t,1.0,compartmentConversion.get(m.sourceCompartment()),metaboliteConversion.get(m.metabolite()));
meta.affectLeft(t,1.0,compDescriptor.getKey(),m2);
}
}
}
/**
* Links the source-specific metabolites representing the same compounds in the shared compartments, by creating a shared "pool" entity
* alongside their interconversion reactions.
* @param meta the meta-network
*/
protected void linkCompoundsInSharedComp(BioNetwork meta) {
//loop over each shared compartment
for(BioCompartment sharedComp : metaCompComposition.keySet()){
//retrieve all metabolite components that has been previously set, using whole compartment fusing or individual additions
BioCollection<BioMetabolite> content = sharedComp.getComponentsView().stream()
.filter((e) -> e.getClass().equals(BioMetabolite.class))
.map(o -> (BioMetabolite)o)
.collect(BioCollection::new,BioCollection::add,BioCollection::addAll);
//all entities that represent the same compounds from different source are grouped
Map<String, List<BioMetabolite>> compoundGroups = content.stream().collect(Collectors.groupingBy(getSharedIdFunction));
//for each group, create a "pool" metabolite that represent them
for(Map.Entry<String, List<BioMetabolite>> group : compoundGroups.entrySet()){
BioMetabolite pool = this.entityFactory.createPoolCompound(group.getValue(),sharedComp);
meta.add(pool);
meta.affectToCompartment(sharedComp,pool);
//for each member of the group, create a reversible reaction linking them to their "pool" counterpart
for(BioMetabolite e : group.getValue()){
BioReaction r = this.createLinkWithSharedPool.apply(e,pool);
meta.add(r);
meta.affectRight(r,1.0, sharedComp,e);
meta.affectLeft(r,1.0, sharedComp,pool);
}
//if option selected, add exchange reaction to the pool for flux modeling
if(addExchangeReaction){
BioReaction r = this.createPoolExchangeReaction.apply(pool);
meta.add(r);
meta.affectLeft(r,1.0, sharedComp,pool);
}
}
}
}
}
package fr.inrae.toulouse.metexplore.met4j_core.biodata.multinetwork;
import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioNetwork;
public interface MultiNetworkBuilder {
/**
* add network into meta-network
* @param bn
*/
public void add(BioNetwork bn);
/**
* create a new network which encompass all added networks
* @return
*/
public BioNetwork build();
}
package fr.inrae.toulouse.metexplore.met4j_core.biodata.multinetwork;
import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioCompartment;
import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioEntity;
import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioMetabolite;
import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioNetwork;
import lombok.Setter;
import lombok.SneakyThrows;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.function.BiFunction;
import java.util.function.Function;
import static fr.inrae.toulouse.metexplore.met4j_core.utils.StringUtils.isVoid;
/**
* Factory to create new instances of BioEntity using prefixed ids from user-defined alias, in order to avoid id conflicts between subnetworks
* in a meta-graph.
**/
public class PrefixedMetaEntityFactory implements MetaEntityFactory {
Map<BioNetwork,String> sourcePrefixMap;
@Setter
protected String poolPrefix;
@Setter
protected String sep = "_";
public PrefixedMetaEntityFactory(Map<BioNetwork,String> sourcePrefixMap, String poolPrefix){
this.sourcePrefixMap=sourcePrefixMap;
this.poolPrefix=poolPrefix;
}
/**
* create prefixed id. This function will be called to create a new id for a BioEntity, using the
* alias of the network it comes from (if it exists) and its original id.
*/
public BiFunction<String, BioNetwork, String> addSourcePrefix = (id, bn) -> isVoid(sourcePrefixMap.get(bn)) ? id : sourcePrefixMap.get(bn)+sep+id;
/**
* create sharedCompartment-suffix id
*/
public BiFunction<String, BioCompartment, String> addCompSuffix = (id, comp) -> id+sep+comp.getId();
/**
* create sharedCompartment-prefix id
*/
public BiFunction<String, BioCompartment, String> addCompPrefix = (id, comp) -> comp.getId()+sep+id;
/**
* remove prefix-id from network alias
*/
public Function<String, String> removeSourceSuffix = id -> {
for(String s : sourcePrefixMap.values()) {
id = id.replaceAll("^" + s + sep,"");
};
return id;
};
/**
* create a pool-prefix id. This is used to identify a pool of compounds originating from different subnetworks.
*/
public Function<String, String> addPoolFlag = (id) -> poolPrefix+sep+id;
@SneakyThrows
@Override
public <E extends BioEntity> E createMetaEntity(E originalEntity, BioNetwork source) {
return newEntityInstance(originalEntity, this.addSourcePrefix.apply(originalEntity.getId(),source));
}
@SneakyThrows
@Override
public BioMetabolite createSharedCompound(BioMetabolite entity, BioCompartment sharedCompartment) {
return newEntityInstance(entity, this.addCompSuffix.apply(entity.getId(),sharedCompartment));
}
@SneakyThrows
@Override
public BioMetabolite createPoolCompound(Collection<BioMetabolite> entities, BioCompartment sharedCompartment) {
BioMetabolite entity = entities.iterator().next();
return newEntityInstance(entity, removeSourceSuffix
.andThen(s -> addCompPrefix.apply(s,sharedCompartment))
.andThen(addPoolFlag)
.apply(entity.getId()));
}
private static <E extends BioEntity> E newEntityInstance(E entity, String newId) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
E newEntity = (E) entity.getClass().getDeclaredConstructor(String.class).newInstance(newId);
newEntity.setName(entity.getName());
newEntity.setSynonyms(new ArrayList<>(entity.getSynonyms()));
newEntity.setComment(entity.getComment());
newEntity.setRefs(new HashMap<>(entity.getRefs()));
newEntity.setAttributes(new HashMap<>(entity.getAttributes()));
return newEntity;
}
}
package fr.inrae.toulouse.metexplore.met4j_core.biodata.multinetwork;
import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioCompartment;
import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioMetabolite;
import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioNetwork;
import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioReaction;
import org.junit.BeforeClass;
import org.junit.Test;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Set;
import java.util.stream.Collectors;
import static org.junit.Assert.*;
public class TestMetaNetworkBuilder {
public static BioNetwork bn1, bn2, bn3, bn4;
public static BioMetabolite a1,b1,c1,c1ex,c2,c2ex,d3, d3ex, f3, d4, d4ex;
public static BioCompartment co1in, co1ex, co2in, co2ex, co3in, co3ex,co4in, co4ex,medium,medium2;
public static BioReaction r1, r3, tc1, tc2, td3,td4;
public static BioNetwork initBump() {
HashMap<BioNetwork,String> alias = new HashMap<>();
alias.put(bn1,"model1");
alias.put(bn2,"model2");
alias.put(bn3,"model3");
alias.put(bn4,"model4");
medium=new BioCompartment("medium");
medium2=new BioCompartment("medium2");
CommunityNetworkBuilder builder = new CommunityNetworkBuilder(medium);
builder.addNewSharedCompartment(medium2);
PrefixedMetaEntityFactory factory = new PrefixedMetaEntityFactory(alias,"pool");
factory.setSep("_");
builder.setEntityFactory(factory);
builder.setAddExchangeReaction(false);
builder.add(bn1);
builder.add(bn2);
builder.add(bn3);
builder.add(bn4);
builder.bumpCompartmentIntoSharedCompartment(bn1,co1ex,medium);
builder.bumpCompartmentIntoSharedCompartment(bn2,co2ex,medium);
builder.bumpCompartmentIntoSharedCompartment(bn3,co3ex,medium);
builder.bumpCompartmentIntoSharedCompartment(bn4,co4ex,medium2);
builder.bumpCompartmentIntoSharedCompartment(bn4,co4ex,medium);
return builder.build();
}
public static BioNetwork initFuse() {
HashMap<BioNetwork,String> alias = new HashMap<>();
alias.put(bn1,"model1");
alias.put(bn2,"model2");
alias.put(bn3,"model3");
alias.put(bn4,"model4");
medium=new BioCompartment("medium");
medium2=new BioCompartment("medium2");
CommunityNetworkBuilder builder = new CommunityNetworkBuilder(medium);
builder.addNewSharedCompartment(medium2);
PrefixedMetaEntityFactory factory = new PrefixedMetaEntityFactory(alias,"pool");
factory.setSep("_");
builder.setEntityFactory(factory);
builder.setAddExchangeReaction(false);
builder.add(bn1,co1ex);
builder.add(bn2,co2ex);
builder.add(bn3,co3ex);
builder.add(bn4);
builder.fuseCompartmentIntoSharedCompartment(bn4,co4ex,medium2);
return builder.build();
}
public static BioNetwork initFuseIncremental() {
HashMap<BioNetwork,String> alias = new HashMap<>();
alias.put(bn1,"model1");
alias.put(bn2,"model2");
BioCompartment medium0=new BioCompartment("medium");
CommunityNetworkBuilder builder = new CommunityNetworkBuilder(medium0);
PrefixedMetaEntityFactory factory = new PrefixedMetaEntityFactory(alias,"pool");
factory.setSep("_");
builder.setEntityFactory(factory);
builder.setAddExchangeReaction(false);
builder.add(bn1,co1ex);
builder.add(bn2,co2ex);
BioNetwork firstIter = builder.build();
System.out.println(Arrays.toString(bn1.getMetabolitesView().stream().map(x -> x.getId()).toArray()));
System.out.println(Arrays.toString(bn1.getReactionsView().stream().map(x -> x.getId()).toArray()));
System.out.println("+");
System.out.println(Arrays.toString(bn2.getMetabolitesView().stream().map(x -> x.getId()).toArray()));
System.out.println(Arrays.toString(bn2.getReactionsView().stream().map(x -> x.getId()).toArray()));
System.out.println("=");
System.out.println(Arrays.toString(firstIter.getMetabolitesView().stream().map(x -> x.getId()).toArray()));
System.out.println(Arrays.toString(firstIter.getReactionsView().stream().map(x -> x.getId()).toArray()));
BioMetabolite[] pool1 = firstIter.getCompartment("medium")
.getComponentsView().stream()
.filter(e -> e instanceof BioMetabolite)
.filter(m -> m.getId().startsWith("pool_"))
.toArray(BioMetabolite[]::new);
for(BioMetabolite pool : pool1){
firstIter.removeOnCascade(firstIter.getReactionsFromMetabolite(pool));
}
firstIter.removeOnCascade(pool1);
System.out.println("->");
System.out.println(Arrays.toString(firstIter.getMetabolitesView().stream().map(x -> x.getId()).toArray()));
System.out.println(Arrays.toString(firstIter.getReactionsView().stream().map(x -> x.getId()).toArray()));
medium=new BioCompartment("medium");
medium2=new BioCompartment("medium2");
builder = new CommunityNetworkBuilder(medium);
builder.addNewSharedCompartment(medium2);
alias = new HashMap<>();
alias.put(firstIter,"");
alias.put(bn3,"model3");
alias.put(bn4,"model4");
builder.setEntityFactory(new PrefixedMetaEntityFactory(alias,"pool"));
builder.setAddExchangeReaction(false);
builder.add(firstIter,medium0);
builder.add(bn3,co3ex);
builder.add(bn4);
builder.fuseCompartmentIntoSharedCompartment(bn4,co4ex,medium2);
BioNetwork output = builder.build();
System.out.println(Arrays.toString(output.getMetabolitesView().stream().map(x -> x.getId()).toArray()));
System.out.println(Arrays.toString(output.getReactionsView().stream().map(x -> x.getId()).toArray()));
return output;
}
@BeforeClass
public static void beforeClass() {
bn1 = new BioNetwork("bn1");
bn2 = new BioNetwork("bn2");
bn3 = new BioNetwork("bn3");
bn4 = new BioNetwork("bn4");
a1 = new BioMetabolite("a_in","a");
b1 = new BioMetabolite("b_in","b");
c1 = new BioMetabolite("c_in","c");
c1ex = new BioMetabolite("c_ex","c");
r1 = new BioReaction("r1");
tc1 = new BioReaction("tc");
co1in = new BioCompartment("in");
co1ex = new BioCompartment("ex");
bn1.add(a1,b1,c1,c1ex,r1,tc1,co1in,co1ex);
bn1.affectToCompartment(co1in,a1,b1,c1);
bn1.affectToCompartment(co1ex,c1ex);
bn1.affectLeft(r1,1.0,co1in,a1);
bn1.affectLeft(r1,1.0,co1in,b1);
bn1.affectRight(r1,2.0,co1in,c1);
bn1.affectLeft(tc1,1.0,co1in,c1);
bn1.affectRight(tc1,1.0,co1ex,c1ex);
c2 = new BioMetabolite("c_in","c");
c2ex = new BioMetabolite("c_ex","c");
tc2 = new BioReaction("tc");
co2in = new BioCompartment("in");
co2ex = new BioCompartment("ex");
bn2.add(c2,c2ex,tc2,co2in,co2ex);
bn2.affectToCompartment(co2in,c2);
bn2.affectToCompartment(co2ex,c2ex);
bn2.affectLeft(tc2,1.0,co2in,c2);
bn2.affectRight(tc2,1.0,co2ex,c2ex);
d3ex = new BioMetabolite("d_ex","d");
d3 = new BioMetabolite("d_in","d");
f3 = new BioMetabolite("f_in","f");
r3 = new BioReaction("r2");
td3 = new BioReaction("td");
co3in = new BioCompartment("in");
co3ex = new BioCompartment("ex");
bn3.add(d3ex,d3,f3,r3,td3,co3in,co3ex);
bn3.affectToCompartment(co3in,d3,f3);
bn3.affectToCompartment(co3ex,d3ex);
bn3.affectLeft(td3,1.0,co3in,d3);
bn3.affectRight(td3,1.0,co3ex,d3ex);
bn3.affectLeft(r3,1.0,co3in,d3);
bn3.affectRight(r3,1.0,co3in,f3);
d4 = new BioMetabolite("d_in","d");
d4ex = new BioMetabolite("d_ex","d");
td4 = new BioReaction("td");
co4in = new BioCompartment("in");
co4ex = new BioCompartment("ex");
bn4.add(d4,d4ex,td4,co4in,co4ex);
bn4.affectToCompartment(co4in,d4);
bn4.affectToCompartment(co4ex,d4ex);
bn4.affectLeft(td4,1.0,co4in,d4);
bn4.affectRight(td4,1.0,co4ex,d4ex);
}
@Test
public void testCompoundsFuse(){
BioNetwork meta = initFuse();
assertEquals(14,meta.getMetabolitesView().size());
assertNotNull(meta.getMetabolite("model1_a_in"));
assertNotNull(meta.getMetabolite("model1_c_in"));
assertNotNull(meta.getMetabolite("model1_c_ex"));
assertNotNull(meta.getMetabolite("model2_c_ex"));
assertNotNull(meta.getMetabolite("model2_c_in"));
assertNotNull(meta.getMetabolite("pool_medium_c_ex"));
assertNotNull(meta.getMetabolite("pool_medium_d_ex"));
assertNotNull(meta.getMetabolite("pool_medium2_d_ex"));
}
@Test
public void testReactionsFuse() {
BioNetwork meta = initFuse();
assertEquals(10, meta.getReactionsView().size());
assertNotNull(meta.getReaction("poolReaction_model2_c_ex"));
assertNotNull(meta.getReaction("poolReaction_model1_c_ex"));
assertNotNull(meta.getReaction("poolReaction_model3_d_ex"));
}
@Test
public void testCompartmentFuse(){
BioNetwork meta = initFuse();
assertEquals(6,meta.getCompartmentsView().size());
}
@Test
public void testCompoundsFuseIncremental(){
BioNetwork meta = initFuseIncremental();
assertEquals(14,meta.getMetabolitesView().size());
assertNotNull(meta.getMetabolite("model1_a_in"));
assertNotNull(meta.getMetabolite("model1_c_in"));
assertNotNull(meta.getMetabolite("model1_c_ex"));
assertNotNull(meta.getMetabolite("model2_c_ex"));
assertNotNull(meta.getMetabolite("model2_c_in"));
Set<String> metabolites = meta.getMetabolitesView().stream().map(x -> x.getId()).collect(Collectors.toSet());
assertTrue(metabolites.contains("pool_medium_model1_c_ex")||metabolites.contains("pool_medium_model2_c_ex"));
assertNotNull(meta.getMetabolite("pool_medium_d_ex"));
assertNotNull(meta.getMetabolite("pool_medium2_d_ex"));
}
@Test
public void testReactionsFuseIncremental() {
BioNetwork meta = initFuseIncremental();
assertEquals(10, meta.getReactionsView().size());
assertNotNull(meta.getReaction("poolReaction_model2_c_ex"));
assertNotNull(meta.getReaction("poolReaction_model1_c_ex"));
assertNotNull(meta.getReaction("poolReaction_model3_d_ex"));
}
@Test
public void testCompartmentFuseIncremental(){
BioNetwork meta = initFuseIncremental();
assertEquals(6,meta.getCompartmentsView().size());
}
@Test
public void testCompoundsBump(){
BioNetwork meta = initBump();
assertEquals(19,meta.getMetabolitesView().size());
assertNotNull(meta.getMetabolite("model1_a_in"));
assertNotNull(meta.getMetabolite("model1_c_in"));
assertNotNull(meta.getMetabolite("model1_c_ex"));
assertNotNull(meta.getMetabolite("model2_c_ex"));
assertNotNull(meta.getMetabolite("model2_c_in"));
assertNotNull(meta.getMetabolite("pool_medium_c_ex_medium"));
assertNotNull(meta.getMetabolite("pool_medium_d_ex_medium"));
assertNotNull(meta.getMetabolite("pool_medium2_d_ex_medium2"));
}
@Test
public void testReactionsBump() {
BioNetwork meta = initBump();
assertEquals(16, meta.getReactionsView().size());
assertNotNull(meta.getReaction("poolReaction_model2_c_ex_medium"));
assertNotNull(meta.getReaction("poolReaction_model1_c_ex_medium"));
assertNotNull(meta.getReaction("poolReaction_model3_d_ex_medium"));
assertNotNull(meta.getReaction("transport_model1_c_ex_to_medium"));
assertNotNull(meta.getReaction("poolReaction_model4_d_ex_medium2"));
assertNotNull(meta.getReaction("poolReaction_model4_d_ex_medium"));
assertNotNull(meta.getReaction("transport_model4_d_ex_to_medium2"));
assertNotNull(meta.getReaction("transport_model4_d_ex_to_medium"));
}
@Test
public void testCompartmentBump(){
BioNetwork meta = initBump();
assertEquals(10,meta.getCompartmentsView().size());
}
}
......@@ -57,7 +57,6 @@ import java.lang.reflect.Method;
import java.net.URL;
import java.util.Comparator;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
public class GenerateGalaxyFiles extends AbstractMet4jApplication {
......
package fr.inrae.toulouse.metexplore.met4j_toolbox.reconstruction;
import fr.inrae.toulouse.metexplore.met4j_core.biodata.*;
import fr.inrae.toulouse.metexplore.met4j_core.biodata.multinetwork.CommunityNetworkBuilder;
import fr.inrae.toulouse.metexplore.met4j_core.biodata.multinetwork.PrefixedMetaEntityFactory;
import fr.inrae.toulouse.metexplore.met4j_io.annotations.network.NetworkAttributes;
import fr.inrae.toulouse.metexplore.met4j_io.jsbml.reader.JsbmlReader;
import fr.inrae.toulouse.metexplore.met4j_io.jsbml.reader.Met4jSbmlReaderException;
import fr.inrae.toulouse.metexplore.met4j_io.jsbml.reader.plugin.*;
import fr.inrae.toulouse.metexplore.met4j_io.jsbml.units.BioUnitDefinition;
import fr.inrae.toulouse.metexplore.met4j_io.jsbml.writer.JsbmlWriter;
import fr.inrae.toulouse.metexplore.met4j_io.jsbml.writer.Met4jSbmlWriterException;
import fr.inrae.toulouse.metexplore.met4j_toolbox.generic.AbstractMet4jApplication;
import fr.inrae.toulouse.metexplore.met4j_toolbox.generic.annotations.EnumFormats;
import fr.inrae.toulouse.metexplore.met4j_toolbox.generic.annotations.EnumParameterTypes;
import fr.inrae.toulouse.metexplore.met4j_toolbox.generic.annotations.Format;
import fr.inrae.toulouse.metexplore.met4j_toolbox.generic.annotations.ParameterType;
import org.kohsuke.args4j.Option;
import java.util.*;
import java.util.function.Function;
import static fr.inrae.toulouse.metexplore.met4j_toolbox.generic.annotations.EnumFormats.Sbml;
import static fr.inrae.toulouse.metexplore.met4j_toolbox.generic.annotations.EnumParameterTypes.InputFile;
import static fr.inrae.toulouse.metexplore.met4j_toolbox.reconstruction.CreateMetaNetwork.strategy.by_name;
public class CreateMetaNetwork extends AbstractMet4jApplication {
//arguments
@Format(name = Sbml)
@ParameterType(name = InputFile)
@Option(name = "-n1", aliases = {"--network1"}, usage = "input SBML file: path to first network, in sbml format.", required = true)
public String sbml1FilePath;
@ParameterType(name = InputFile)
@Option(name = "-n2", aliases = {"--network2"}, usage = "input SBML file: path to second network, in sbml format.", required = true)
public String sbml2FilePath;
@Option(name = "-n1ex", aliases = {"--external1"}, usage = "external compartment identifier in first network.", required = true)
public String external1;
@Option(name = "-n2ex", aliases = {"--external2"}, usage = "external compartment identifier in second network.", required = true)
public String external2;
@Option(name = "-n1px", aliases = {"--n1prefix"}, usage = "prefix that will be added to first network's entities identifiers", required = false)
public String n1prefix = "Net1_";
@Option(name = "-n2px", aliases = {"--n2prefix"}, usage = "prefix that will be added to second network's entities identifiers", required = false)
public String n2prefix = "Net2_";
@Option(name = "-k", aliases = {"--keepCompartment"}, usage = "keep the original external compartments in the meta-network, otherwise, they will be fused into the new shared external compartment", required = false)
public boolean keepCompartment = false;
@Option(name = "-n1meta", aliases = {"--firstAsMeta"}, usage = "Treat first network as meta-network, allowing more than two sub-models with iterative fusions. This will overwrite shared compartment and pool compounds (which must follow the \"pool_\" prefix convention) and will ignore --n1prefix argument", required = false)
public boolean firstIsMeta = false;
enum strategy {by_metanetx, by_name, by_id}
@Option(name = "-mc", aliases = {"--mergingCriterion"}, usage = "field used to identify the same metabolites across the two different networks. " +
"\"by_name\"/\"by_id\" can be used if names/identifiers are consistent and unambiguous across source models, \"by_metanetx\" can be used if models contains MetaNetX identifiers in annotation field using standard miriam format.")
public CreateMetaNetwork.strategy mergingCriterion = by_name;
@ParameterType(name = EnumParameterTypes.OutputFile)
@Format(name = EnumFormats.Sbml)
@Option(name = "-o", usage = "output meta-network SBML file", required = true)
public String outputPath = null;
public static void main(String[] args) throws Met4jSbmlWriterException {
CreateMetaNetwork app = new CreateMetaNetwork();
app.parseArguments(args);
app.run();
}
public void run() throws Met4jSbmlWriterException {
if(Objects.equals(this.n1prefix, this.n2prefix)){
System.err.println("Error: prefixes must be different");
System.exit(1);
}
//import networks
System.out.print("Importing network 1...");
JsbmlReader reader = new JsbmlReader(this.sbml1FilePath);
ArrayList<PackageParser> pkgs = new ArrayList<>(Arrays.asList(
new NotesParser(false), new AnnotationParser(true), new FBCParser(), new GroupPathwayParser()));
BioNetwork network1 = null;
try {
network1 = reader.read(pkgs);
} catch (Met4jSbmlReaderException e) {
System.err.println("Error while reading the first SBML file");
System.err.println(e.getMessage());
System.exit(1);
}
BioCompartment co1ex = network1.getCompartment(external1);
if(co1ex==null){
System.err.println("Error: external compartment " + external1 + " not found in network 1");
System.exit(1);
}
if(firstIsMeta){
n1prefix = "";
BioMetabolite[] pool1 = network1.getCompartment(external1)
.getComponentsView().stream()
.filter(e -> e instanceof BioMetabolite)
.filter(m -> m.getId().startsWith("pool_"))
.toArray(BioMetabolite[]::new);
for(BioMetabolite pool : pool1){
network1.removeOnCascade(network1.getReactionsFromMetabolite(pool));
}
network1.removeOnCascade(pool1);
}
System.out.println(" Done.");
System.out.print("Importing network 2...");
reader = new JsbmlReader(this.sbml2FilePath);
BioNetwork network2 = null;
try {
network2 = reader.read(pkgs);
} catch (Met4jSbmlReaderException e) {
System.err.println("Error while reading the second SBML file");
System.err.println(e.getMessage());
System.exit(1);
}
BioCompartment co2ex = network2.getCompartment(external2);
if(co2ex==null){
System.err.println("Error: external compartment " + external2 + " not found in network 2");
System.exit(1);
}
System.out.println(" Done.");
System.out.print("Creating meta-network...");
//setup
BioCompartment medium=new BioCompartment("medium"); medium.setName("medium");
HashMap<BioNetwork,String> alias = new HashMap<>();
alias.put(network1,n1prefix);alias.put(network2,n2prefix);
CommunityNetworkBuilder builder = initMetaNetworkBuilder(medium, alias);
builder.add(network1);
builder.add(network2);
//build meta-network
if(!keepCompartment){
builder.fuseCompartmentIntoSharedCompartment(network1,co1ex,medium);
builder.fuseCompartmentIntoSharedCompartment(network2,co2ex,medium);
}else{
if(firstIsMeta) {
builder.fuseCompartmentIntoSharedCompartment(network1, co1ex, medium);
}else{
builder.bumpCompartmentIntoSharedCompartment(network1, co1ex, medium);
}
builder.bumpCompartmentIntoSharedCompartment(network2,co2ex,medium);
}
BioNetwork metaNetwork = builder.build();
System.out.println(" Done.");
//export the meta-network
System.out.print("Exporting MetaNetwork...");
NetworkAttributes.addUnitDefinition(metaNetwork, new BioUnitDefinition());
new JsbmlWriter(outputPath,metaNetwork).write();
System.out.println(" Done.");
}
private CommunityNetworkBuilder initMetaNetworkBuilder(BioCompartment medium, HashMap<BioNetwork, String> alias) {
CommunityNetworkBuilder builder = new CommunityNetworkBuilder(medium);
PrefixedMetaEntityFactory factory = new PrefixedMetaEntityFactory(alias,"pool_");
factory.addCompSuffix = (id, comp) -> id+"_"+comp.getId();
builder.setEntityFactory(factory);
Function<BioMetabolite, String> getSharedIdFunction;
switch (mergingCriterion) {
case by_metanetx:
getSharedIdFunction = x -> {
try {
BioRef r = x.getRefs("metanetx.chemical").iterator().next();
return r.getId();
} catch (NoSuchElementException | NullPointerException e) {
return "unknown_"+UUID.randomUUID();
}
};
break;
case by_id:
getSharedIdFunction = BioEntity::getId;
break;
case by_name:
getSharedIdFunction = BioEntity::getName;
break;
default:
throw new IllegalArgumentException("Invalid merging criterion: " + mergingCriterion);
}
builder.setGetSharedIdFunction(getSharedIdFunction);
return builder;
}
@Override
public String getLabel() {return this.getClass().getSimpleName();}
@Override
public String getShortDescription() {
return "Create a Meta-Network from two sub-networks in SBML format.";
}
@Override
public String getLongDescription() {
return "Create a Meta-Network from two sub-networks in SBML format. A meta-network is a single model which contains several sub-networks that remains individualized within" +
"the meta-network (as opposed to models fusion), but which can share some of their components with " +
"other sub-networks through a shared \"medium\" compartment.";
}
}