All Downloads are FREE. Search and download functionalities are using the official Maven repository.

it.unibo.alchemist.model.biochemistry.actions.CellTensionPolarization Maven / Gradle / Ivy

There is a newer version: 35.0.2
Show newest version
/*
 * Copyright (C) 2010-2023, Danilo Pianini and contributors
 * listed, for each module, in the respective subproject's build.gradle.kts file.
 *
 * This file is part of Alchemist, and is distributed under the terms of the
 * GNU General Public License, with a linking exception,
 * as described in the file LICENSE in the Alchemist distribution's top directory.
 */
package it.unibo.alchemist.model.biochemistry.actions;

import it.unibo.alchemist.model.actions.AbstractAction;
import it.unibo.alchemist.model.biochemistry.properties.CircularDeformableCell;
import it.unibo.alchemist.model.positions.Euclidean2DPosition;
import it.unibo.alchemist.model.Context;
import it.unibo.alchemist.model.biochemistry.EnvironmentSupportingDeformableCells;
import it.unibo.alchemist.model.Node;
import it.unibo.alchemist.model.Reaction;
import it.unibo.alchemist.model.biochemistry.CircularCellProperty;
import it.unibo.alchemist.model.biochemistry.CircularDeformableCellProperty;
import org.apache.commons.math3.util.FastMath;
import org.danilopianini.lang.MathUtils;

import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * Models the tension polarization of {@link CircularDeformableCell}
 * in an {@link EnvironmentSupportingDeformableCells}.
 */
public final class CellTensionPolarization extends AbstractAction {

    private static final long serialVersionUID = 1L;
    private final EnvironmentSupportingDeformableCells environment;
    private final CircularDeformableCellProperty deformableCell;

    /**
     * 
     * @param node the node
     * @param environment the environment
     */
    public CellTensionPolarization(
            final EnvironmentSupportingDeformableCells environment,
            final Node node
    ) {
        super(node);
        this.environment = environment;
        this.deformableCell = Objects.requireNonNull(getDeformableCell(node),
            "The node must have a " + CircularDeformableCellProperty.class.getSimpleName()
        );
    }

    private CircularDeformableCellProperty getDeformableCell(final Node node) {
        return node.asPropertyOrNull(CircularDeformableCellProperty.class);
    }

    private CircularCellProperty getCircularCell(final Node node) {
        return node.asPropertyOrNull(CircularCellProperty.class);
    }

    private boolean isDeformableCell(final Node node) {
        return getDeformableCell(node) != null;
    }

    @Override
    public CellTensionPolarization cloneAction(final Node node, final Reaction reaction) {
        return new CellTensionPolarization(environment, node);
    }

    @Override
    public void execute() {
        // get node position as array
        final double[] nodePosistion = environment.getPosition(getNode()).getCoordinates();
        // initializing resulting versor
        final double[] resultingVersor = new double[nodePosistion.length];
        // declaring a variable for the node where this action is set, to have faster access
        final Node thisNode = getNode();
        // transforming each node around in a vector (Position) 
        final List pushForces = environment.getNodesWithinRange(
                thisNode,
                environment.getMaxDiameterAmongCircularDeformableCells()).stream()
                .parallel()
                .filter(node -> { // only cells overlapping this cell are selected
                    final CircularCellProperty circularCell = getCircularCell(node);
                    if (!Objects.isNull(circularCell)) {
                        // computing for each cell the max distance among which can't be overlapping
                        double maxDistance;
                        if (isDeformableCell(node)) {
                            // for deformable cell is maxRad + maxRad
                             maxDistance = deformableCell.getMaximumRadius() + getDeformableCell(node).getMaximumRadius();
                        } else {
                            // for simple cells is maxRad + rad
                             maxDistance = deformableCell.getMaximumRadius() + circularCell.getRadius();
                        }
                        // check
                        return environment.getDistanceBetweenNodes(thisNode, node) < maxDistance;
                    } else {
                        // only CellWithCircularArea are selected.
                        return false;
                    }
                })
                .map(node -> {
                    // position of node n as array
                    final double[] nPos =  environment.getPosition(node).getCoordinates();
                    // max radius of n
                    final double localNodeMaxRadius;
                    // min radius of n
                    final double localNodeMinRadius;
                    // max radius of this node (thisNode)
                    final double nodeMaxRadius = deformableCell.getMaximumRadius();
                    // min radius of this node (thisNode)
                    final double nodeMinRadius = deformableCell.getRadius();
                    // intensity of tension between n and this node (thisNode), measured as value between 0 and 1
                    final double intensity;
                    if (isDeformableCell(node)) {
                        localNodeMaxRadius = getDeformableCell(node).getMaximumRadius();
                        localNodeMinRadius = getDeformableCell(node).getRadius();
                    } else {
                        localNodeMaxRadius = getCircularCell(node).getRadius();
                        localNodeMinRadius = localNodeMaxRadius;
                    }
                    // if both cells has no difference between maxRad and minRad intensity must be 1
                    if (MathUtils.fuzzyEquals(localNodeMaxRadius, localNodeMinRadius)
                            && MathUtils.fuzzyEquals(nodeMaxRadius, nodeMinRadius)
                    ) {
                        intensity = 1;
                    } else {
                        final double maxRadiusSum = localNodeMaxRadius + nodeMaxRadius;
                        intensity = (maxRadiusSum - environment.getDistanceBetweenNodes(node, thisNode))
                                / (maxRadiusSum - localNodeMinRadius - nodeMinRadius);
                    }
                    if (intensity != 0) {
                        double[] propensityVector = {nodePosistion[0] - nPos[0], nodePosistion[1] - nPos[1]};
                        final double module = FastMath.sqrt(FastMath.pow(propensityVector[0], 2)
                                + FastMath.pow(propensityVector[1], 2));
                        if (module == 0) {
                            return environment.makePosition(0, 0);
                        }
                        propensityVector = new double[]{
                                intensity * (propensityVector[0] / module),
                                intensity * (propensityVector[1] / module)
                        };
                        return environment.makePosition(propensityVector[0], propensityVector[1]);
                    } else {
                        return environment.makePosition(0, 0);
                    } 
                })
                .collect(Collectors.toList());
        if (pushForces.isEmpty()) {
            deformableCell.addPolarizationVersor(environment.makePosition(0, 0));
        } else {
            for (final Euclidean2DPosition p : pushForces) {
                resultingVersor[0] = resultingVersor[0] + p.getX();
                resultingVersor[1] = resultingVersor[1] + p.getY();
            }
            final double module = FastMath.sqrt(FastMath.pow(resultingVersor[0], 2) + FastMath.pow(resultingVersor[1], 2));
            if (module == 0) {
                deformableCell.addPolarizationVersor(environment.makePosition(0, 0));
            } else {
                deformableCell.addPolarizationVersor(
                    environment.makePosition(resultingVersor[0] / module, resultingVersor[1] / module)
                );
            }
        }
    }

    @Override
    public Context getContext() {
        return Context.LOCAL;
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy